Haxe: The Good, The Bad, and the Ugly
There are a lot of programming languages out there. Literally tons of them. Some are typed, some are not; some interpreted, some are compiled. Some compiled languages are dynamically linked, some are statically linked. Some interpreted languages are good, and some are Ruby. Some languages are designed for the web and some are designed for servers; some are awesome like Javascript, and some are PHP.
I stumbled across a little-known language called Haxe a while back while looking for a way to compile Python into something a little more portable and was immediately impressed. For those of you who are not familiar with Haxe — probably most of you, honestly — it is a statically-typed, explicit-typing-optional, object-oriented meta-language that can produce source and binaries for Java, Python, C++, C#, Neko, Javascript, and a few others. Haxe can be used to write frontend code, backend code, mobile apps, browser apps, and just about anything you want (except for an HTTP server, more on that later). It can also run in a native interpreted mode, meaning that regardless of your compile target you can see changes to your code immediately instead of having to wait for a compile to finish. This is outstanding when writing for a C++ or Java target. So what does Haxe look like? Lets take a quick look.
Haxe will immediately feel familiar to a lot of developers. Take a look at this simple “Hello World” app:
If we run this with haxe -main HelloWorld --interp
we get the output:
$> haxe -main HelloWorld --interp
HelloWorld.hx:4: Hello world!$>
Something a little more complicated from a recent project of mine looks like this:
To anyone that’s worked with TypeScript, C/C++/C#, or Java this looks really familiar. Us Python guys are a little weirded out by insignificant whitespace and curly braces, but its an adjustment I’m willing to make.
So lets take a look at all that Haxe has to offer…
The Good
- Haxe is cool
- Being able to compile my interpreted code down to a binary is wicked cool
- The stdlib is pretty robust, and includes target-specific libraries for lower-level integration into your compile target
- Conditional compilation for different compile targets. Use library A when compiling to C++, and library B when targeting Javascript
- Its fast.
- Anyone familiar with “traditional” programming should feel very at home with Haxe
- SDK/shared library creation is a breeze
- Comes with a package manager
haxelib
and can install packages from both thehaxelib
repository orGithub
- Unlike Python, threads are not CPU-bound by a GIL
- Threads have built-in communication abstractions through the
sendMessage
andreadMessage
methods, no need for semaphores or things like that - Explicit typing is only forced in certain places, like iterators. Types
any
andDynamic
let you get away with doing the lest amount of typing necessary, but even half the time types aren’t required.
The Bad
- The stdlib is woefully lacking in documentation
- Third party libraries seem to be rather stale and not updated very often, and third party support for things like databases seems to be lacking other than the support that’s already baked into the stdlib (MySQL, SQLite)
- Due to its esoteric nature there’s not much on the internets about it. Searching StackOverflow is slightly more difficult than when searching for, say, Python
- Adding external (3rd party) packages requires manually editing your build/run parameters to include the library (
haxe -lib <lib> …
), which is both annoying and ripe for mistakes - Generated source code tends to be rather verbose. The
HelloWorld
example up above generated 15 lines of Python for what could be done in two, and 102 lines of C++. - Maybe its just me, but I hate trailing semicolons in code. Haxe has them. 90% of my compile errors are missed semicolons.
The Ugly
- Haxe has no real HTTP server functionality. While there are 3rd party libraries like
tink
that help with this, they are unnecessarily complex and their documentation is also lacking. - Threading is not supported in
--interp
mode. Once you introduce threading you have to start compiling to test. - Types have too few methods. Type
Thread
only has four methods (sendMessage
,create
,current
, andreadMessage
), methods forthreadId
,cpu
,kill
,active
, and others would go a long way. - Data structures are messy. Haxe has
map
,array
, andanonymous structures
, but most objects seem to work with the slower un-optimizedanonymous structures
rather than the optimizedmap
andarray
. - Basic library support for things like
yaml
,ini
, argument parsing and such don’t yet exist (but is also an opportunity to contribute to the Haxe stdlib)
The Conclusion
Is Haxe anything more than a novelty? I think so. I think there is a very interesting case to be made for a high-level language that transpiles to other lower-level languages. As I’ve already stated, SDK creation is one of those areas, but also just simplifying a codebase across multiple platforms, especially if those platforms include mobile devices.