Requiring a Class argument to have a certain constructor signiature

Haxe has a very powerful reflection API, allowing you to create objects of a class, which you don’t know until runtime.

var u:User = Type.createInstance(User, [“jason”,”mypass”]);
u.save();

Sometimes, you have a method where you want to create a class, but which class is created is specified by the user:

function createUser( cls:Class<User>, u:String, p:String ) {

var u:User = Type.createInstance( cls, [u,p]);
u.save();

}
createUser( StaffMember, “jack”, “mypass” );
createUser( Subscriber, “aaron”, “mypass” );

So far so good.  But what if we have a 3rd user class, “Moderator”, that actually has a constructor that requires 3 arguments, not just the username and password.

createUser( Moderator, “bernadette”, “mypass” );

This compiles okay, but will fail at runtime – it tries to call the constructor for Moderator with 2 arguments, but 3 are required.

My first thought was, can we use an interface and specify the constructor:

interface IUser {

public function new( user:String, pass:String ):Void

}

Sadly in Haxe, an interface cannot define the constructor.  I’m pretty sure the reason for this is to avoid you creating an object with no idea which implementation you are using.  Now that would work for reflection, but wouldn’t make sense for normal object oriented programming:

function createUser( cls:Class<IUser>, u:String, p:String ) {

var u:IUser = new cls(u,p); // What implementation does this use?

}

So it can’t be interfaces… what does work?  Typedefs:

typedef ConstructableUser = {
function new( u:String, p:String ):Void,
function save():Void
}

And then we can use it like so:

function createUser( cls:Class<ConstructableUser>, u:String, p:String ) {

var u:ConstructableUser = Type.createInstance( cls, [u,p]);
u.save();

}
createUser( StaffMember, “jack”, “mypass” );
createUser( Subscriber, “aaron”, “mypass” );
createUser( Moderator, “bernadette”, “mypass” ); // ERROR – Moderator should be ConstructableUser

In honesty I was surprised that “Class<SomeTypedef>” worked, but I’m glad it does.  It provides a good mix of compile time safety and runtime reflection.  Go Haxe!

Accept either String or Int, without resorting to Dynamic

A quick code sample:

`AcceptEither`, a way to accept either one type or another, without resorting to “Dynamic”, and still have the compiler type-check everything and make sure you correctly handle every situation.

Try it on try.haxe.org

The next step would be having Accept2Types, Accept3Types etc, and have a macro automatically build the code for whichever option you ask for.