6.9 Function Bindings

Haxe 3 allows binding functions with partially applied arguments. Each function type can be considered to have a bind field, which can be called with the desired number of arguments in order to create a new function. This is demonstrated here:

class Main {
  static public function main() {
    var map = new haxe.ds.IntMap<String>();
    var f = map.set.bind(_, "12");
    $type(map.set); // Int -> String -> Void
    $type(f); // Int -> Void
    f(1);
    f(2);
    f(3);
    trace(map); // {1 => 12, 2 => 12, 3 => 12}
  }
}

Line 4 binds the function map.set to a variable named f, and applies 12 as second argument. The underscore _ is used to denote that this argument is not bound, which is shown by comparing the types of map.set and f: The bound String argument is effectively cut from the type, turning a Int->String->Void type into Int->Void.

A call to f(1) then actually invokes map.set(1, "12"), the calls to f(2) and f(3) are analogous. The last line proves that all three indices indeed are mapped to the value "12".

The underscore _ can be skipped for trailing arguments, so the first argument could be bound through map.set.bind(1), yielding a String->Void function that sets a new value for index 1 on invocation.

Optional arguments

By default, trailing optional arguments are bound to their default values and do not become arguments of the result function. This can be changed by using an explicit underscore _ instead, in which case the optional argument of the original function becomes a non-optional argument of the result function.

class Main {
  static function test(a:Int, ?b:String):Void {}

  static public function main() {
    var fn = test.bind(1);
    $type(fn); // Void->Void
    fn('foo'); // Compiler error: Too many arguments

    var fn = test.bind(1, _);
    $type(fn); // ?String->Void
    fn('foo'); // works
  }
}
Trivia: Callback

Prior to Haxe 3, Haxe used to know a callback-keyword which could be called with a function argument followed by any number of binding arguments. The name originated from a common usage were a callback-function is created with the this-object being bound.

Callback would allow binding of arguments only from left to right as there was no support for the underscore _. The choice to use an underscore was controversial and several other suggestions were made, none of which were considered superior. After all, the underscore _ at least looks like it's saying "fill value in here", which nicely describes its semantics.