Skip to main content


Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Messages - alpha123

Hellos and Byes / Hey mates
Long time no see. I happened to be browsing Duktape's website and noticed that minisphere uses it, which brought me back here. :)

While I don't think I'll be using Sphere for anything for a while, it's interesting to follow the development of the Sphere-compatible engines.
Engine Development / Re: TurboSphere

I was speaking of adding server-client type facilities that specifically address multiple games running in one instance. I'm just going to leave it be, one game per engine instance, for the foreseeable future.

Ah, like web browser tabs for Sphere games? Yeah, I can't see that being terribly useful. I can think of some cool stuff involving minigames inside e.g. a larger RPG, but there are other ways to do that involving much less effort.


It's true that it does happen (I do the same thing, testing server-client functions without worrying about the network, using two machines, etc.). But having two games share the same backend (more like  how a web browser works) would be tremendously complicated. Simple in theory--but it would be a LOT of work to implement, and would cause at least some overhead when only one game is running.

Better to work on other things then, and maybe revist this in a few years after everything else is done. =P


Running two instances of the engine at once is still quite possible, though. That should always be possible.

Good, I was getting a little worried there. :)


Considering a debugger, it would be fairly simple to make a rudimentary piping plugin for TurboSphere that would let a second instance examine the JS stack on another instance.
But V8 already has GDB debugging integration. Or so they say--TurboSphere is always distributed with a V8 library that has that enabled. But there is, as with almost everything Google does, no documentation on how it works or how to use it.

That would be awesome, because my current solution is extremely hackish. It involves recompiling the code to add instrumentation and then using the network functions to push to the debugger whenever something changes. Suffice it to say, it doesn't work currently. :P
Engine Development / Re: TurboSphere
Er, I often play two Sphere games at the same time on the same machine to test networked games. Also I've been thinking of/slowly working on a Sphere Debugger that runs as a game and attaches to another running game.

GNUstep is kind of a joke though. I think I looked at it once and sort of lost interest once I realised they'd only implemented to like OS X 10.4 or something similarly old.
I suggest just keeping it Mac-exclusive. You can't really have a native Mac app that's portable; Apple's frameworks make sense on OS X and not really anywhere else (plus they're not really implemented anywhere else).
Libraries / Re: Link.js v0.2.8b

Yeah, my library is a pain to add things on to it. It's very "class heavy" - like how compilers are written. So adding a new feature means adding a lot of little stuff, most of which is boilerplate stuff that I can't seem to get rid of effectively.

I know how that goes. My library pretty much is a compiler, actually (and a reasonably advanced one at that, capable of function inlining, loop unrolling, and specializing certain chains of functions). It does make adding new methods pretty tedious. To do your example, it would be

Code: (javascript) [Select]
For.prototype.add = function (num) {
    this.nodes.push(new AddNode(num))
    return this

function AddNode(num) { this.num = num }
AddNode.prototype.compile = function () {
    return 'a+=' + this.num + ';'

For([1, 2, 3]).add(1).toArray()  // [2, 3, 4]

which is surprisingly not all that different. It is, however, fairly tedious, so I developed an easier (but less performant) way to extend it by taking advantage of the fact that every array operation1 can be done as a map, filter, or reduce.2

Code: (javascript) [Select]
For.addFilter('even', function (element) { return element % 2 == 0 })
For.addMapper('add', function (element, index, amount) { return element + amount })
For.addEvaluator('sum', function (accumulator, element) { return accumulator + element })

For.range(10).even().add(5).sum()  // 45

All these methods do is create a function on For.prototype that does all the boilerplate stuff, and then calls map, filter, or reduce with a function that does more boilerplate and then calls the actual extension function.
There is another extension method, addFilterMap, which is a little more complicated (it generates a sequence of method calls instead of just a single one to map/filter/reduce) but allows both transforming and testing an element at the same time.


The above is how 80% of the library is implemented; which is why you can see how it is so fast. It runs at nearly the speed of traversing your standard every-day link list. That's the whole secret. I really want to expand to a binary tree, but such a format is not always easy to use when given an already linear array, but my hope would be to add binary searching to it - crazy stuff for a 0.3.0 release someday in the future.

I really like how that's implemented; it is simple, effective, and is very friendly to modern JS engines which will do a lot of optimization for you. It really is very fast too; I was only able to beat Link in Chrome by less than 10 milliseconds when I added loop unrolling. I still haven't beaten Link in Firefox, and this is in a test that is rather contrived to play off of my library's specific optimizations. :P
The binary tree thing would be quite interesting. I was thinking of extending my library to binary heaps and linked lists, but that would A) add a lot of complexity and B) I don't really know enough about data structures or algorithms to do that effectively.

Also, brony alert! (Bronies are cool, I bear no ill will against them :) )

Oh, alright, you found me. :D

1With some exceptions like drop and take. For/Dash/name-TBD's extension system doesn't quite support extending with methods like that yet, but the general groundwork is there.
2Technically I suppose map and filter can be implemented on top of reduce, but that would kill For's performance.
Libraries / Re: Link.js v0.2.8b

Huh, I thought it was called For.js because, when I read it, it reads as 'forges'.

That's kind of clever, I hadn't thought of that. :P It was named because it was intended to allowed you to write for loops with a higher-level syntax, but really it just became a faster clone of Lazy.js with a completely different implementation and some cool features.

alpha123: There already exists a library called lo-dash (a pun on Underscore), naming it Dash might imply a nonexistent connection and confuse people.  I'm thinking that might be why Radnen chose not to use it.

I'm definitely aware of Lo-Dash, and the name Dash is actually slightly intended to imply that (mostly) nonexistent connection. ;P (They're pretty close API-wise, and the implementations are actually oddly similar in that they involve code generation and eval().) I thought Radnen didn't use it because Link implied that it's like LINQ, and you didn't like the sound of Dash.js. :P

Sure. Link is only very fast in Chrome, it is fast (faster than Lazy) in other browsers, but I don't think it's a universal solution. In Sphere it's not all that great (esp. on small arrays), so I've been using a different code called 'List.js' for arrays where I do one thing to it, and Link if I need to do more than one thing.

Huh, for me the difference between Link and other libraries is actually bigger in Firefox than in Chrome. I haven't tested my library in Sphere for a while and I'm not really sure how it will perform. On the one hand, since it generates code, it relies mainly on a fast eval() and that the generated code will be well optimized. Sphere doesn't really have either of those, but on the other hand, my library doesn't have a deep call stack, which Lazy and Link tend to create and Sphere generally doesn't handle too well.

Anyway, that is an odd thing that Chrome does with prototypes, and probably has to do with V8's "hidden classes" optimization thing. My library just assigns to prototype directly anyway, but that's good to know.

Well yeah, that was true (and still is), I don't really like the name Dash.  It's basically just a pun on all the other similarly named libraries with no real meaning of its own other than "this is fast"--which is useful info, but not really the #1 priority with a library like this.  Otherwise you'd just roll your own for loops! :-).

If you have any better ideas I'd be happy to hear them. To be honest 90% of the reason I like the name Dash is so that I can use this as the mascot.... ;D

Incidentally, my library does roll its own for loops.... :P Hence the original name For.js, but I decided that it wasn't the greatest idea to name a library after its implementation (which is subject to change; I'm not sure generating for loops at runtime is the best choice in some circumstances).

Expect an alpha release of For/Dash/name-TBD soon. (Name suggestions are appreciated. :P) It's getting pretty close to having a full API; it's not nearly as comprehensive as Link's yet, but one of its main features is that it's fairly easy to extend.
Libraries / Re: Link.js v0.2.8b
Radnen, would you mind if I used your proposed name Dash.js for my library (formerly known as For.js)? The fact that it compiles for loops behind the scenes is just an implementation detail now, and I don't feel like For.js fits it too well any more. I rather like the sound of Dash (it implies speed); if you don't mind, I think I'd rename it to that.

(Link.js is still, somehow, faster than it, BTW.)
Programming / Re: JS Bind method for your Sphere games
That would be like overwriting Math.floor() with a function that does ~~n. Sure it's faster, but it does something different, albeit similar. I think it would be much better to just grep (or ack, or ag) through the code and replace Function#bind() that way. Or at least less confusing.
Programming / Re: JS Bind method for your Sphere games
While it's useful, since it's very far from ECMA compliant, you really shouldn't put it in Function#bind(). That is expected to be ES5-compliant. Maybe make it its own function or something.

Hard coding the arguments in is pretty clever, if very inflexible. arguments is notoriously slow in JS.
Libraries / Re: [code] Link.js v0.2.3
You could do that with zip().

Code: (javascript) [Select]

Link(array1).zip(array2).each(function ([a, b]) {
  // do whatever

Would be slightly less elegant without SpiderMonkey's JS extensions, but you get the idea.

EDIT: Actually never mind, that does something different, I misread your post.
~Radnen: code tag fix
Engine Development / Re: Sphere SFML v0.75alpha

Do you have a link for json2.js?

json2.js (GitHub), although I recommend json3.js (GitHub).
Libraries / Re: [code] Query.js for Sphere

Alpha123: I had the exact same idea, but then I realized how much trouble it would be to create a feature complete thing like Lazy. Also, it's kinda like cheating. :P

In order to reasonably achieve feature-completeness and extensibility, For.js actually uses two types of methods: the ones that are compiled into the loop, like map() and filter()--these are the ones that have to be fast. For other, less common methods it simply calls out to regular functions, although that is not completed yet I had a prototype that was capable of it so it's at least doable.
I thought it would be a relatively easy way to get good performance too, until I was barely beating (and often losing to) Lazy.js even in Sphere 1.6. xP Then I got out the bag of JS black magic. I'm still amazed by how much function inlining boosts performance, even in a modern environment like Chrome. With function inlining off it's consistently ~200ms slower than Lazy.js on the 25m element array. Whatever Lazy.js does, it's very, very good. Since function inlining is fundamentally rather limited I need to come up with some more general optimizations to beat it, let alone Query2. Cheating is hard. :(


My trick is to back out of execution when you no longer need it.

I'm wondering if I can pull something like this off with aggressive usage of break and continue. The data flow in Query2 makes this a lot easier for you, I think.


It has, after all far more optimization potential, but at the expense of a lot of creator-struggle.

I think yours has more potential for algorithmic optimizations which are usually more effective. On the other hand, my type of inlining is simply not possible in your system, and it's a big win for the common case.
Oddly enough For.js is only around ~550 lines right now, and I think at least 30% of that is documentation and comments explaining what the heck I'm doing. Granted, the API is very small, but the core parts are in place. The creator-struggle hasn't bitten me quite yet (although perhaps the fact that at least 30% of the code is comments means it actually has...).


Oh, and in Sphere Query2 at least works, but it is flawed: Sphere's JS has bad stack-frame performance, so much so it can be worse that Query at times. So a for-loop generator like yours is perhaps the only best option. But in a good environment like Chrome, it's starting to be clear just how much faster than Lazy my code is by witnessing the speed gains from their more powerful stack frame handling.

Could you try trampolining the function calls to avoid creating extra stack frames? I'm not quite sure how your code works, but people have been able to sort of implement tail-call optimization that way. Emulating the stack in JS is rather expensive though, so you'd have to weight the benefits against some possibly large overhead.
Libraries / Re: [code] Query.js for Sphere
@NEO: The reason it doesn't perform those is because those would require actually parsing the inlined functions. Currently it simply tokenizes them and does some very basic parsing to verify that they're safe to inline. It then does a little more parsing to replace variable names, but never at any point generates a proper AST. I could consider that, especially since in the end I'll likely be creating an AST of some sort from the method calls to then compile to the for loop. I currently think full parsing of functions would add significant overhead for relatively small gain, but if anyone can think of some really useful optimizations that involve rewriting the input to higher-order functions I could implement a parser and compiler.

Your first optimization is actually implemented now, because I restructured a bit of the compilation so that it avoids the continue altogether by wrapping the rest of the code in a non-negated if statement. The example now compiles to
Code: [Select]

function (s, l, b, p, f, a) {

mainly because it's shorter (invoking the Function constructor has high overhead, so the less I feed it the better) and simpler (one less operation).

I believe n|0 is the fastest Math.floor()-type thing, but none of the bitwise hacks are quite equivalent to Math.floor() with regard to negative numbers. So it couldn't do that type of optimization automatically, although isInt() could be written with n|0 and For.js would still happily inline it.

I have been paying more attention than usual (i.e. none) to FBNil's School of Micro-Optimizations for this, because it's meant to be blazing fast even in Sphere 1.5. Still, I think at this point I'm likely to get bigger gains by doing less work, not by doing work faster. Whatever Radnen is doing, I imagine it's aggressively delaying evaluation to avoid doing much work. For.js does not do as much of that currently. His architecture lends itself more to that sort of thing; For.js would need some restructuring and probably a proper optimizing compiler to achieve that level. At the moment it relies mainly on clever and bizarre things like decompiling and inlining functions. Which if I may say so is pretty darn sick, but has only very small gains from this point and is of limited utility anyway since it's only possible for a few functions.
Off-Topic Discussions / Re: Happy new year!
Happy New Year! I'm interested to see what the Sphere community comes up with this year. Even though I'm not that active around here any more, I will still pop in and watch progress, especially on TurboSphere and Sphere SFML which interest me greatly.