I often run into people confused as to how to use Haxe or, where exactly it fits into a project pipeline.
For the newcomer, Haxe is a high level modern programming toolkit that compiles to a multitude of languages (c#, c++, java, js, python, php, etc). You can visit Haxe.org for a closer look - in the mean time, here is a broad strokes view of what Haxe is and can do.
This is part one.
Here is part two.
The versatility confusion matrix
Haxe is an extremely versatile toolkit for cross platform and cross target development (more on this soon). It is a tool that fits many uses which by nature makes it very hard to pinpoint it to a list of "What is it" or "What is it for". It's difficult to say - because you can do basically anything using it.
Let's take a language people don't get “confused” by (or do they?) and ask the same questions : What is C#? What can I use it for? What about C++? Or Java? Or JS? Or Python? Every single one of these languages are versatile, and let you :
- write a console application
- write a game / game engine
- write a web page/app/backend
- write a high level utility script
Since Haxe is a programming language, it does all of these things as well. Simple enough! Bonus: because Haxe becomes other languages (including the ones in our example), it can do everything those languages do as well.
The Haxe Toolkit
Now that we see that Haxe includes a programming language, what else does the Haxe Toolkit include? more details on haxe.org
- The programming language
- The (cross) compiler
- The standard library
The programming language
As mentioned, it's a programming language. It's modern, it's high level, it's strictly typed and includes access to the underlying target languages and native platforms.
The cross compiler
What do you do with some code written in the Haxe programming language? Feed it to the compiler!
What does that compiler generate? Code in a target language and depending on the target, a binary of sorts. Let's look at a simple example.
App.hx as a Haxe class, let's see an example of how to get a target language file from a Haxe file:
haxe -main App -python app.py
haxe -main App -js app.js
Edit: I was reminded that although python has been available as a target for almost a year in repo, and is listed on the main home page, that it is in fact a 3.2 feature and is not available in 3.1.3 stable. It will be shipping sometime in the near future - Sorry for the lack of clarity on that!
This is covered in more detail later on, with more examples of real world uses and other targets. The compiler includes many other utilities as well :
noteable compiler utilities
There are so many to list, because of the wide number of targets, but I'll short list some of my favourite ones :
- Insanely fast. Building complex projects in < 1s usually, which of course varies by the target language and the complexity of the output code, your disk write speeds, etc - but the compiler itself is so fast you'll often wonder if it worked because it blinked by.
- Documentation xml output can be generated directly from Haxe itself, which will return the information about every type and all the documentation within the files for consumption. This data is pretty brutal, but can be coerced using the Haxe xml parser itself fairly easily into other data like JSON. From it, though, really useful and fully in depth documentation can be generated. Of couse the Haxe API itself uses it.
- Code completion is handled by the compiler itself. You tell it a file location and the command line options, it will return xml information about the completion at that point. This allows third party plugins and tools to fully utilitize the features of the language in their interface, if they provide the capability to do so. Included in the compiler is a code completion cache server, which will stay running and cache types and classes for projects, ensuring that there is never delays in completion.
The standard library
When you're writing code in general, and especially cross platform code, it's really helpful (and often important) to have code that works the same across all targets.
This is what the standard library is for. There are a myriad of classes in there, way too many to list here, but let's pick a few for examples of the type of thing that are "built in" to the language and are often available on every target.
The full Haxe api listing is here
common cross platform examples
var object = haxe.Json.parse(str);
var string = haxe.Json.stringify(object,null,4);
var encoded = haxe.crypto.Base64.encode(source);
- There is also CRC, md5, sha1, sha256 etc
var xml = haxe.xml.Parser.parse(source, strict);
for(node in xml) var attribute = node.get('example');
var str = haxe.Serializer.run(object);
var object = haxe.Unserializer.run(str);
var data = haxe.Http.requestUrl('http://example.com');
- available on cpp, cs, java, js, macro, neko, php, python
target specific utilities
On top of common tools and types and utilities, the standard library includes a lot of options for each target individually, allowing maximum use of the underlying language features.
Some easy examples : File/FileSystem access. These are only available on certain platforms where it makes sense. When compiling to other targets, these types are not available.
Also remember : these are all strongly typed API's.
Say you were writing something for the python target, and you needed access to the python standard library.
import python.lib.Glob; ... var list:Array<String> = Glob.glob('path/');
If you're writing a web page, you might want access to the native api, like
js.Browser.window.alert('hello from haxe');
Maybe you wanted to create an element:
var element = new js.html.DivElement(); element.style.width = '99px'; js.Browser.document.appendChild(element);
sys target example
A good number of platforms support the sys types.
var data = sys.io.File.getContent('path.txt');
In many of these cases you might want to use
#if python of
#if sys and so on, to prevent code from trying to compile for the wrong target and throw errors your way.
Using the generated code
As this is a large and open ended topic, I will only give a few simple examples for you to understand how to use the low level code output in another project or as part of a project. This is ALWAYS going to be dependent on the actual language output you are targeting. For example, C# can use dll's really easily, or C++ target can generate as a static library, etc. Each target usage differs based on where you will use it.
JS is straight forward, you simply load it in an HTML file in the browser or in node.js or other interpreters.
There are two main use cases here, one is that your application boots itself up (using the regular
static function main entry point in the
-main class, and the second is that you're complimenting existing js code with some js code from Haxe.
In the first case, you would just include the generated js file as usual, with
The second case would require you to call into or out of the Haxe code. This is a js specific problem, and is solved with js specific solutions. You would be able to for example, store a value in the global scope from Haxe, or call global stuff from Haxe that the non Haxe code exposes.
With Haxe code written say as a library for use in C# tools (like Unity, Mono, etc) you can directly generate a .dll file for immediate use as a reference. The code can also be included in the project manually, and the
-D no-root flag will keep all the Haxe code in it's own namespace to avoid conflicts.
You can also use Haxe with Unity directly.
A good example of a Java use case would be an Android plugin. If you add the
android.jar library to your class path in the hxml file or command line, you can compile immediately usable jar files from Haxe code that call the native android api's directly.
Here's an example class, written in Haxe, that opens a URL in the device default browser as a new Activity. This Haxe class is compiled into a .jar file, and is then usable in any android project thanks to the Haxe cross compiler, and the Haxe java backend.
Haxe is a low level toolkit
Most people encounter Haxe through a framework using the Haxe toolkit to deploy to multiple targets - this is because Haxe is designed to be a lower level set of tools to efficiently and adeptly handle cross platform development.
This also means that there are things you will need a framework in order to achieve them. To answer the question "how do I draw graphics with Haxe" is a bit of a misnomer, the toolkit (and the language) cannot answer this for you.
Let's look at js:
- You could draw with Canvas/HTML5
- You could draw with WebGL
- You could draw with Processing.js, Pixi.js, phaser.js etc
Every single target has a plethora of options available for every specific need.
Thus, frameworks, bindings, native externs and cross target implementations are written by third party developers, to give you access to these things in your Haxe code.
Continuing with the js target example, how about JQuery? What about node.js? Pixi.js? Phaser? What about some audio for the js web target, like Howler.js.
All of these offer strongly typed, ready to use bindings for just one of the many targets.
Certain targets like C++ and C# are a bit more complicated due to the nature of different compilers and runtimes, but there are still many frameworks and bindings available to you for any number of things.
Notes about the backends
Often a target has it's own implementation of all of the backend details, and standard lib implementation specifics. These are an automatic dependency when targeting that platform, as they make all the generated code work, but the process is transparent to you provided you have them installed through haxelib. For example,
haxelib install hxjava would install the java backend,
hxcpp are the C# and C++ backends respectively.
Notes about neko
Neko is a VM (Virtual Machine) that runs code written in the neko programming language. The neko language is not intended to be programmed manually, but rather is a generated language that allows running the code (often bytecode) across multiple platforms through the virtual machine. You can think along the lines of lua or other VM's that run bytecode interpreted at runtime.
So why do you see neko mentioned in Haxe discussions?
- Neko is a Haxe target
Haxe code can be compiled directly to neko bytecode, which can then be loaded into a neko VM. A good example:
mod_nekowhich runs on Apache web server, can run Haxe code on the server side, much like you would install mod_php and run php files, mod_neko runs neko files. Lot's of frameworks and developers use neko on the server, and code their backend in Haxe. The haxelib server and site are all written in Haxe.
- Neko bytecode is cross platform
This makes it a great candidate for using Haxe to write cross platform command line utilities. The reason you see neko when Haxe is running, is because the Haxe toolkit includes neko (and its tools) and uses it for many things. Again, haxelib, the Haxe package manager, allows packages to include a
run.nfile, a neko file compiled from Haxe, that will run when a user calls
haxelib run yourpackage. This is powerful because you only need one file, and it will run on every target that you support in your code, with full access to the standard library and more.
Neko is useful for these types of tools and includes features like
nekotools -boot bytecode.n, which will generate a binary for a plaform (like a windows exe or mac binary), should you want to distribute the tool standalone. Neko also compiles really quickly, because Haxe is fast at compiling and the generated bytecode has no compile step.
Finally, because Haxe includes neko in the installer and is dependent on it, it's a reliable tool that many frameworks and developers lean on to do their bidding. If you're going to be using Haxe and writing tools, it's a great option for scripting user facing utilities that will have no dependencies and be cross platform.
notes about platform vs target
- A platform is a host environment that runs code.
- A target is a language target that haxe compiles to
The important distinction is that a single language target can and will run on multiple platforms. For example, the c++ backend will run on iOS, Android, Mac, Windows, Linux, Blackberry, Tizen and quite a few others. It also supports custom toolchains for things like consoles and native cross compilers and makes it easy to compile the c++ using it's build tools, to any C++ supported platform.
JS output can run on node.js or other interpreter based platforms. Python can run on any platform with a python interpreter. PHP as well. The targets and platforms are not the same thing.
On the shoulders of a giant
Because Haxe is this flexible, because it's a low level toolkit, many frameworks are built on top of Haxe in order to achieve some goal. A few examples of these, some of which you have probably heard of:
- NME (native media engine)
- long standing media and game framework loosely based on flash API's
- the original backbone of many frameworks and tools
- OpenFL (Open Flash Library)
- forked from NME originally to align closer to Flash API
- general purpose framework based on Flash 2D API
- many game frameworks built on top of it, HaxeFlixel, HaxePunk, etc
- many tools built dependent on it like haxeui
- large, powerful MVC web backend/frontend framework
- compiles to php/neko
- Flash/WebGL/HTML5/Android/iOS 2D game engine using AIR
- Nape physics
- cross target high performance 2D physics engine
Frameworks determine workflow
Now that we are higher up, there are workflows determined by the higher level frameworks you'll probably be using, which means you might not have to call the Haxe command line directly much at all (if ever).
Integration with IDE's like Flash Develop, they supporting Haxe as a relatively first class part of the editor. The features and decisions Flash Develop makes are often informed by the IDE that implements them. For tools and frameworks, you'll find that a variety of options will exist under different circumstances that meet different needs in the eco system.
know your tools
Having frameworks built on frameworks using tools that are built into IDE's made by various third parties can lead to layers of indirection. The best approach is to pick a framework or tool or work directly with Haxe itself and try to understand the stack you are using to achieve your goals. There is no way around it, and this applies to any language/platform/programming tool. Try and know more about how things fit together to serve your needs.
platform and target considerations
Framework/tool specific choices can also lead to isolating a specific subset of targets, so of course you shouldn't assume that because Haxe can target so many languages, every framework automatically works on all of those options. A lot of times that doesn't even make sense (there is no concept of a console application on web or mobile etc).
These choices are expected and good, and are often goal oriented, man power based or related to logical reasoning.
A great example is Flambe, which targets swf/js Haxe targets primarily. It then leverages AIR for mobile/desktop and HTML5/WebGL for browsers. This maximizes the focus and provide something that does what it sets out to do well, while leveraging the power of the Haxe toolkit to achieve it.
Flambe uses npm (node package manager) to install, and has it's own command line utilities to build and run the games, including automatic asset updates while the game is running in the browser and lots more. This means a tight integration with the framework and the best possible options to be avaible to the end user, things that the Haxe toolkit couldn't (and shouldn't) provide.
If you wanted to jump to using another framework, it will probably (unless it is built on Flambe) have a completely different workflow. This is great, and normal/expected, and allows a rich set of tools across a variety of preferences, goals, target languages and platforms to cover a wide range of use cases.
As you'll notice the amount of use cases spirals rapidly when you consider that the output code can be used in a multitude of ways. This is a valuable and powerful thing about Haxe and what makes it quite hard to describe.
Hopefully this helps someone starting out with Haxe or explains why I choose it for everything I write, why I created http://snowkit.org and use Haxe for my games and engines.
You can view all my ramblings about Haxe here.