callback and _

You are viewing an old version of this entry, click here to see latest version.

_ (underscore)

HaXe 3.0 provides an intuitive language construct for partial function application, also known as currying. Call a function with an underscore character in place of one or more argument values, and it will return a wrapper function that takes only those "fill-in-the-blank" arguments. Then when you call this wrapper function, it will call the original function and automatically insert the values for the other arguments you specified.

public function sumXplusY(x:Int, y:Int) {return x + y;}
public static function main(){
    var sumXplus2 = foo( _, 2 );
    var sum4plusY = foo( 4, _ );
    trace(sumXplus2(3)); // traces 5
    trace(sum4plusY(3)); // traces 7
}

Currently this syntatic sugar requires the -D haxe3 compiler switch, otherwise you must use the more verbose style described below.

Callback

In older versions (2.8 and prior), currying was applied with the callback function. callback creates a wrapper function around another function, automatically inserting arguments into the original function that will persist every time the wrapper function is called.

public function foo(x:Int, y:Int) {return x+y;}

public static function main(){
    // creates a copy of foo() that automatically makes the first argument a 4
    var foo_cb = callback(foo,4);
    trace(foo_cb(5)); // traces 9
}

Callback is similar to what you can accomplish through some of the methods in the Reflect API. However, with callback you can only insert arguments in order (i.e. you must specify the first argument before you can specify the second argument, and so forth). In this way, callback was more limited than any of the Reflect methods, but the new 3.0 syntax is more flexible.

Usage

The big advantage of using callback (or the new syntax) is that it is a fully typed call, for both arguments and arity, so you get type-safe code (vs. Reflect). This is very useful in functional routine arguments, such as the Lambda methods, which typically require a function that takes only one argument. For example, you can do this:

// calculate the powers of 3 for each element of an array,
// and return the results in a new array:
trace(Lambda.map( [10,2,36,4,5], Math.pow(3, _)));

// that is the same as this:
trace(Lambda.map( [10,2,36,4,5], callback(Math.pow, 3)));

// which is also the same as this:
trace(Lambda.map( [10,2,36,4,5], function(x) { return Math.pow(3, x);}));

With the new syntax you can also do this:

// calculate the squares of each element of an array
trace(Lambda.map( [10,2,36,4,5], Math.pow(_, 2)));

That cannot be done with the old syntax.

version #20107, modified 2014-05-17 17:51:30 by galundin