There are other paths for Haxe, although they are probably not pretty. That is Haxe -> C++ -> Emscripten -> asm.js. Then there is another, Haxe -> Java -> GWT -> JS.
I think Haxe is underappreciated for areas other than game development. You can write serverside logic with it (compile to js for node.js, php, neko, java, c#, python), and target flash and js in the browser.
I agree. Haxe has a very vibrant community but I'm still surprised it never got bigger than it has.
I used it extensively at Chumby on apps for the devices since the alternative was using ActionScript 2 (which is basically JavaScript minus the more modern features post-ECMAScript3).
Given roughly the same code (minus the syntax differences for each), the Haxe compiler would run much faster than Adobe's and almost always generated faster bytecode even though I was targeting Adobe's own Flash AVM1. Plus haxe let me use all the goodies the language offers, like non-brain-dead scoping, static typing and the macro system.
Haxe + Flambe really is a nice combination for developing 2D games for us at the moment. We cover old browsers with Flash (IE6 etc.) and modern browsers - either canvas or WebGL, with almost no concern about which ends up running in the end on the client. It almost feels like magic at times. The compiler also generally seems very fast as well.
Sublime text makes a nice(ish) IDE with free plugins.
Additionally, we can relatively easily compile out iOS and Android binaries should we want/need to. It's a very nice system to work with and has caused us very little problems with just getting things done.
> A lesson to future compiler makers: if you want your compiler to be really fast use OCaml, not Java!
Another option the author could have explored is js_of_ocaml. It compiles OCaml bytecode to JavaScript. It works quite well in my (somewhat limited) experience.
GWT is still a very viable option for writing JavaScript applications, if not actually the best one. It is one of (or the?) first transpiling tools and very mature and feature rich (transparent RPC/serialization, obfuscation/deobfuscation, IDE integrated debugging, i18n, resource bundling, code splitting, JavaScript interoperability, etc.).
The author seems to have a bit of a bias (Dart's designers "ate too much Java for breakfast"), but Java is rock solid, and being able to write the entire application, from the client and the domain model on down to the backend, is a major boost. GWT also has a vibrant community (see f.ex. the GWT.create() event across US and Europe: http://gwtcreate.com/) and lots of invention and development going on, with a huge new release (2.7) coming up.
GWT won on size across the board and beat everything but C on performance. Of course, this benchmark, like most, is biased. It uses a lot of polymorphism, and GWT does exceptionally well at removing polymorphic dispatch statically.
Are you sure? I have never looked at Java implementation of Box2D used in this benchmark, but Dart version is definitely not that polymorphic in its hottest function which corresponds to this Java one:
It looks like mostly a bunch of floating point math to me with not that many calls out.
Another interesting thing I noticed now is that Java version has all vector math inlined manually, while in Dart version it is not the case (at least not entirely if I remember correctly - we want to write high level code and let optimizer do what it can).
No, I'm not sure. I profiled the hand-written JS function one time and noticed a lot of time spent in polymorphic methods. Also, this coincided with an optimization in GWT to improve hidden class V8 optimizations and speed went up by 300%, so it seemed related to polymorphism.
The vector math does look like an apples-to-oranges comparisons. Simple methods like cross-product will inline in GWT as well. The biggie seems to be the elision of the temporary, we'd need something like C++'s return value optimization to get rid of that.
I'll try rerunning the bench by adding calls to cross-product to see how it fares. Actually for us, we weren't as interested in comparing the speed to Dart as much as comparing it to the JVM version. The slowdown there is on the order of 50% which isn't bad. In the original thread on G+ I noted there's no way this can be considered an apples-to-apples comparison because they're not running the same code (the port's from Box2D differ), but Joel's whole Box2D benchmark suite kind of rests on this.
> I'll try rerunning the bench by adding calls to cross-product to see how it fares.
btw, if you have a moment I would really appreciate if you tell me how to reproduce +Brandon Donnelson results. It's hard to figure out from those photos which version of GWT should I get from where and what to compile with it. I was not sure if I supposed to check out Joel's code AS IS or I should get it from some other place, etc.
It's been a while, but you'll probably need to built a custom version of GWT using this patch (https://gwt-review.googlesource.com/#/c/8590/) as we had to roll back the V8 optimization due to a catastrophic performance regression in IE11.
Brandon's results were culled from the informal results I posted in Joel's G+ thread (which he independently verified). From the thread you can see I was quite disbelieving myself and not at all ready to plant a flag, I even implemented a verification in the GWT version to ensure that the final resting state of the system converged to what it was supposed to.
Some very tiny patches to GWT (adding dummy random unique properties to prototypes, an optimization to HashMap.put/ArrayList.get, etc) have lead to 300-500% speedups in our benchmark server, meanwhile really complex ones actually slowed things down, or did nothing.
For example, I added asmjs output to GWT (where possible in method bodies, not a truly strict-check), I also implemented an optimization which auto-converts Java classes to typedarrays where possible, e.g.
class Vec3 {
float x, y, z;
// getters and setters
}
Would require the class into a bag of static methods and rewrite the field accesses into indexes into a typed array. This turned out not to be a win when benchmarked on Box2D, probably for other reasons.
Interesting, why the dummy random unique properties? Some sort of type information/hidden class pollution workaround?
Converting classes into typed arrays/typed array buffers is something that seems like it should be awesome but in practice isn't. :( I've tried it extensively in JSIL as well and it seems to only be a win if you have thousands of them in an array - for individual instances you get murdered. Maybe this will get fixed by Typed Objects if they ever land in ES.
I am very interested in better ways to transform Java into asmjs, but I think we'll need typed objects and/or some way to deal with garbage collection. The latter is a particular problem, well, if we take the route we did with j2objc, we can just punt and require manual annotations to break reference cycles, implementing our own ref-counting/ARC scheme on top of typed arrays, but it would be nice if someone asmjs and GC could play nicely together, without implementing the Boehm collector. :)
Well, I have a relatively firm plan to work on getting asm.js v2 + typed objects finalized and produce a proof-of-concept compiler targeting them, so hopefully I can help push them along! It'd be great to understand GWT's needs here.
I didn't notice that the Typed Object spec supports "new" heap allocation, if this'll work with asmjs, than awesome.
GWT's needs are primarily two fold:
1) recognize Java types that can be promoted to struct-types. GWT already knows how to do this as it has passes to convert all methods of a class to monomorphic/static dispatch, meaning the prototype only has to contain field values. Thus if a Java type has no polymorphic methods, and all fields are either primitives, or references to other 'struct' types, then the compiler can emit typed objects.
2) Since Java is a GC'ed language, GWT currently isn't in the business of implementing a memory management scheme. We rely on Javascript to do this. The current problem with strict asmjs output is we'd need to allocate typed arrays and our own memory management scheme. There's not much appetite for that right now, but I suppose it could change in the future.
The second link only shows perf numbers for some of the options, compared to GWT, but it's clear from the first link - which lacks GWT - that GWT would lose not just to C and the JVM, but also to asm.js, CrossBridge, and PNaCl.
Overall GWT is a decent performer, but not near the top. It is however nice that GWT can beat standard JS by a small amount.
I lumped Emscripten/Asmjs in with the "C" benchmarks. The JVM verson of JBox2D 2.3 actually performs on par with asmjs (Firefox 27 numbers when this was taken). JVM went from 5ms (jbox2d 2.2) vs (jbox 2.3) 3ms, so that puts the GWT version at about 50% (~6ms).
It might be possible to locate a few hot methods and instrument just those with asmjs assertions and see if it has any effect. I don't know how Firefox reacts to something that's "half-way" asmjs (asserts types on math expressions, but still uses objects with fields instead of typedarrays), but FTLJIT and Turbofan are claiming they'll make use of them even in the non-strict case. We'll see.
Right now I'm spending most of the my time implementing Java8 lambdas, Promises, and all that good stuff that removes the "tax" of java boilerplate so I don't have much time to explore it, but given how early Turbofan seems to be, waiting might be good anyway.
I recall that my first introduction to GWT was Google Wave... sadly, while it was groundbreaking in showing how you could write complex, testable code that ran both in the browser and on the server, Wave wasn't a great showcase for GWT's performance characteristics. Now, with Node.js and its relatively stable module system filling that isomorphic+maintainable gap, it's unclear what GWT brings to the table unless you have reasons to use Java (like a team with a lot of expertise in it, or a legacy codebase, for instance). I'm curious to hear if GWT's compiler can do significant performance optimizations on modern JIT JS engines, as compared to well-written Javascript that follows roughly the same module/class structure.
1) already attached to Java language and toolchain
2) code sharing with Server, Android, etc (see Google Inbox)
3) Optimized compiles (Closure can also do the same for JS)
Modern JIT JS engines do remove the need for most performance optimizations, but GWT and Closure Compiler have never really biased towards runtime performance, they have almost exclusively focused on code size.
GWT does do some optimizations that help with performance, but most web apps are not bottlenecked by raw Javascript performance. However for mobile apps in particular, especially those on slow networks all over the world, shipping smaller code will matter for latency, startup time, memory usage, etc.
Subjective perception of speed in web browsers is very often a function of DOM complexity, and excessive style recalc, layout, paint. You could reduce the JS execution to zero and still end up with an app that feels laggy as hell.
I don't recommend people switch to GWT unless they have a reason to use Java. You can implement a lot of these optimizations on whatever language you like.
My philosophy is to use whatever you feel most comfortable in. I'm kind of tired of 2 decades of language wars in the tech community. I work on GWT because I used it for my own startup several years ago and needed to make patches to the project to improve it, and now I just like working on the compiler because it is an interesting problem space.
Personally, if I was writing non-Web apps, Rust looks to me like an exciting language. I'm more on the side of "more typing" as opposed to less (Go), and for non-Web apps, I like to work on games, and there, I want absolute best performance. Outside of C/C++, Rust looks to be the best new game in town (ok, I've heard good things about D). Swift, I don't trust as being too proprietary and wedded to Objective-C semantics.
Now, I wonder who's going to write a Rust-to-JS compiler? :)
A lot of Rust people are interested in Rust -> LLVM -> Emscripten -> JS, but there's still a lot of work to do. https://github.com/rust-lang/rust/issues/2235 - and integration is literally going on as we speak, https://github.com/kripken/emscripten-fastcomp/issues/51 . I'm also very excited about Rust - so many other languages that give its kind of safety guarantees are either horribly hard to performance-optimize, or very difficult for someone from a C/C++ background to reason about. As the ecosystem and availability of libraries improves, I see it becoming every bit as big as Go is.
> I don't know how exactly Emscripten handles the uints question but everything worked well and pretty fast without me having to worry about it and having to turn uints into ints.
Isn't that a bit cheaty? IE is potentially a lot faster with that change, which Haxe's port benefits from. Haxe's port got more work put into, so proclaiming it a winner because Emscripten was already pretty fast without any work put into the port makes me doubtful of the results.
(Also, Haxe's UInt 0xFFFFFFFF not being converted to -1 sounds like a bug waiting to happen.)
Hmm, well. For emscripten, the code is run through the C preprocessor, then clang and LLVM have to sucessively "lower" it several times, and then generate asm.js.
Haxe, on the other hand, is a high-level language that could be compiled to JavaScript much more simply.
But then, I'm not sure why Dart would be slow, then, given it's also quite high-level. Tree-shaking of the standard library? Having to compile the standard library?
Haxe is multi-targeted. It compiles to PHP, C++, Neko Bytecode, etc.
Being a high-level language, and using the same compiler infrastructure, it would have to be transpiled into a fairly low-level IR for the consumption of the various backends before being spit out as JS again.
I think the fact that its high level makes it much LESS simple.
It definitely isn't just mapping Haxe constructs to JS. It is much too feature rich.
For Dart, it wasn't fully valid. The problem was that they used the 32-bit VM on a 64-bit machine. Of course, the Dart team is working on fixing the number boxing on the 32-bit version that resulted in the poor performance, but the 64-bit performance would've been better, as outlined in the article.
I think Haxe is underappreciated for areas other than game development. You can write serverside logic with it (compile to js for node.js, php, neko, java, c#, python), and target flash and js in the browser.