Haxe Delegates 1.0.0 Release: Faster Type-Safe Function Types

Hi All,

Following on from this topic I created several months ago (thanks life), I am happy to announce a first major release with a majority of the original problems fixed. You can find it here:

Please feel free to post bugs here, or issues to github.

So what’s the deal?

These Delegate objects can be faster on some platforms (~40% faster for non-inlined functions and ~200% faster for inlined on the hxcpp and js targets). Very useful within performance-critical code where delegates/functions need to be called, however delegate building is much more expensive.

Why?

Some Haxe targets are required to unbox value types from function types when called (which then need to be garbage collected). By encapsulating function calls, we can avoid this unboxing and even enforce type-strictness on function type parameters. The following example will fail:

var delegate : Delegate<Dynamic->Void> = DelegateBuilder.from(myFunction);

// Must have Dynamic as first argument...
public function myFunction(a : Int) : Void {
    trace(a);
}

How to use it:

Import haxe.delegates.* and simply use the delegate type with a function type as your parameter, like so:

var delegate : Delegate<(Int, Int)->Int> = DelegateBuilder.from(myFunction);

public function myFunction(a : Int, b : Int) : Int {
    return a + b;
}

or,

var delegate : Delegate<(Int, Int)->Int> = DelegateBuilder.from((a : Int, b : Int) -> (a+b : Int)));

For inlined functions, it is important to use the cast notation (x : Type). This is not for casting the value, instead it is used by the builder to resolve the return type without the need to determine it implicitly.

What’s actually going on?

These macros generate concrete types at compile time. As such, they’re not designed to replace Haxe function types (which are light-weight and useful when used during start-up). The trade-off when using delegates for speed is a slightly bigger source-code.

Future work:

It may be possible to wrap delegates that get generated by their respective builders into singletons, or caching, to reduce any performace impacts during run-time if one wishes to create delegates frequently.

5 Likes