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
It is probably easiest to read this as "increment is the add function with the first parameter always equal to 1."increment = curry(add, 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.