¸.·´¯`·.´¯`·.¸¸.·´¯`·.¸><(((º>
Dojo Cookies Make Curry

Via Alex yesterday I discovered the nice set of tutorials over at dojocampus.org cutely dubbed "cookies." Reading through the article Alex highlights on dojo.hitch I even learned something new. Turns out dojo.hitch isn't just a nice tool for taming the beast that is Javascript scoping, it can also make a nice curry.

For the uninitiated, currying generally refers to the act of transforming a function that takes X arguments into a function that takes Y arguments, where Y < X.

As a trivial example, consider the implementation of an increment function, that is, a function which takes an integer n and returns n+1. Assuming the existence of a function add which returns the sum of its two arguments, we can implement increment as

increment = curry(add, 1)
It is probably easiest to read this as "increment is the add function with the first parameter always equal to 1."

Dojo offers this functionality bound up in the already useful dojo.hitch. Normally passed just a scope object and a function, hitch actually takes an arbitrary number of arguments, all of which (except the first two) are passed as arguments to the function when it is finally called. As an example, let's look at an interactive session I used to explore this function:

x = {a: 1}

y = {a:2, f: function(b,c,d){print(this.a); print(b); print(c); print(d);}}

y.f(3,4,5)
2
3
4
5
dojo.hitch(x, y.f)(3,4,5)
1
3
4
5
dojo.hitch(x, y.f, 3, 4, 5)()
1
3
4
5
Essentially, we are setting the value of the parameters of y.f before y.f is called. This can be very useful.

One real world example of where this can be used is in asynchronous function handling like the kind encountered when using dojo.xhrGet. As of Dojo 0.9, dojo.xhrGet returns a dojo.Deferred. This object, a port of the MochiKit Deferred which is a port of the Twisted Deferred, is contract that an associated task will have a return value at some point. Given a deferred d, callbacks can be added with d.addCallback(callbackFunction), where callbackFunction is a function that takes one argument.

What if I want to pass more than one argument to a callback function? Because Javascript supports closures, we could just define the callback function in place and reference variables in scope, like:

var extraInfo = 1;
d.addCallback(function(deferredReturnValue){
    return deferredReturnValue + extraInfo;
});
Alternatively, we could use dojo.hitch to curry our callback into a single parameter function:
var extraInfo = 1;
var callback = function(extraInfo, deferredReturnValue){
    return deferredReturnValue + extraInfo;
}
d.addCallback(dojo.hitch(this, callback, extraInfo));
This lets us define the callback function wherever we like and frees us from the constraint that callback functions take only one argument.