nadako's rants

Multi-type abstracts in haxe

If you ever wondered how Map creation works in Haxe, here's how: it's a special kind of abstract - the multi-type abstract. It differs from normal abstract in that it is constructed via special @:to functions, so when you call new Map(), it actually selects one of these functions depending on given type.

Now, on the syntax. To create your own multi-type abstract, first you define its underlying type to be some base type with type parameters. Anything will do: interface, class, typedef.

Then you add @:multiType meta-data to your abstract. Then you declare the new function so you can create this abstract with new keyword, but don't write its body, so it becomes quite like an interface function declaration.

Finally, you define @:to functions that create concrete classes. These functions differ from the @:to functions used to convert an instance of abstract to some type. They are static and must have one argument of an underlying type with type parameter you want. This argument is not used (actually it's always null), but needed for the type system to choose correct @:to function for a given type.

Well, example is worth a thousand words, so here you are:

interface IA<T>
{
}

class StringA implements IA<String>
{
    public function new() {}
}

@:multiType
abstract A<T>(IA<T>)
{
    public function new();

    @:to static inline function toStringA(t:IA<String>):StringA
    {
        return new StringA();
    }
}

class Sample
{
    static function main()
    {
        var a = new A<String>();
    }
}

The main function will be compiled to this (javascript):

Sample.main = function() {
	var a = new StringA();
}

This feature is quite useful when you want to abstract multiple implementations depending on type (like it's done with Map), but it wasn't really documented, so I had to read some sources and experiment.

Actually, it may be not documented on purpose because the syntax is subject to change in future versions? I don't know, gotta find out :-)