14
14
Jan 2013

Using Haxe to Solve Problems

it's not polite to point

The most fun thing about programming in Haxe is just messing with its power. Its compiler is fast, there’s support for some sweet macros, there’s compile-time types that dissolve at runtime, there’s Iterators and Enums, there’s inlining, there’s metadata… and let’s not forget that this language compiles to multiple targets, and does a damn good job at it!

Of course, you shouldn’t use these features for their own sake; you should only consider them when you have some problem that they solve. For instance, if you’re manipulating vertices on a 3D mesh, you might feel compelled to throw some helper functions into your Vertex class, but for the Flash target, this increases the memory footprint of a Vertex instance. With the using mixin, you can write a class of static utility functions that pretend they are methods on Vertex. That’s what using is for- separating sets of methods from the data they operate on, while keeping the syntax simple.

But don’t do that just because you can.

The ROPES recently presented me with an interesting problem: how can we represent memory addresses in Haxe? The ROPES’s internal data structure consists mostly of Arrays, and I wanted two objects to exchange a reference to an Int within an Array, rather than its value. Haxe belongs to a family of languages that don’t support references to primitive types; they are always passed by value. What to do?

The immediate solution is hopefully obvious to you– a reference to an Int in an Array is simply a reference to the array, combined with the index of the integer within the array. And since the references that the ROPES uses are meant to be used on any array, we reduce the solution to just storing the integer’s array index. I’ve used this solution previously in AS3.

Unfortunately, our solution has a small caveat– the data type of what we’re referencing is the same as the data type of the references themselves. It’s very easy to swap them by mistake:

for (i in 0...100) {
var val = array[i];
if (val % 5 > 2) array[val] = 0; // Whoops!
}

Lots of bugs that people write in AS3 and JavaScript don’t get caught until the code is run. Haxe’s static typing makes it easy to catch bugs of a certain variety– such as when a value has the wrong type. If we represent references as {index:Int}, we can prevent the above mistake with Haxe’s type checker.

But {index:Int} is much slower than Int on any platform. So, we map our pointer type to {index:Int} when a compiler flag is set, and we map it to Int when that compiler flag is absent. Finally, we write inline static functions that operate on the type, so we don’t have to write compiler flag dependent code in our projects.

Haxe is surprisingly adept at expressing these useful syntactical structures that aid in programming and dissolve when you no longer need them. Let’s take this pointer idea further; say we want to prevent pointers from being used at inappropriate times– as if we were making them read-only, at runtime, for certain intervals. Well, we could create a type called PointerSet like this: {setID:Int}. Our function for making pointers will require a PointerSet parameter, and our debug pointer type will have an additional setID value that matches its corresponding PointerSet. Finally, we write inline functions to “lock” and “unlock” PointerSets, which simply entails looking up a boolean in an array and assigning it a value. Pointers with “locked” PointerSets are then prevented from being used to assign values. Of course, once the programming is complete and we pry off the compiler flag, all this waltzing around with PointerSets literally disappears from the delivered program.

You can find my implementation of Pointers here. So the next time you’re debating with your friends over whose language is the most beneficial, consider this: does your language of choice help you to be a better programmer?


You can leave a response, or trackback from your own site.

Leave a Reply