Currying in JavaScript

I was trying to implement something a bit like tabbing functionality in JavaScript the other day and ran into a problem. I had elements that would switch tabs – so I made these all of “tabswitch” class and cooresponding elements for the content of the “tab” class. I wanted to assign a onclick handler to a switcher element based on it’s position only. So clicking the 3rd switch element would switch to the 3rd tab. Something like this:

< .... class="tabswitch" onclick="show(3);">

But I wanted to do it in a way that didn’t involve writing this down for each element. I wanted to iterate through everything of the “switcher” class and assign it a handler when the page loaded.  Following on that path, it seems like you would want something like this in an onload handler:

var switchers = document.getElementsByClassName("tabswitch");
for(var i = 0; i < len; i++)
   switchers[i].onclick = function () {show(i)};

of course, this doesn’t really work out because when it comes time for the handler to execute, ‘i’ will be bound to a temp containing the last number assigned to ‘i’. So clicking any of these elements would switch to the last tab, not at all what we want! What we need is for the current value of ‘i’ to be “shoved” into the function when we assign this onclick handler.  One way of achieving this is by using “eval” to dump the entire contents of the function with the value for ‘i’ interpolated in the appropriate places (and even this only works if you don’t need to change i in the function). This is not very pretty.

Several languages have a beautiful solution to this problem called currying (and others have something called partial evaluation).  In this example, we would want assign the onclick handler to a new (“curried”) function that is defined like so:

var showi = show(i);
switchers[i].onclick = showi; 

(note: we’ll need a way to distinguish a call from a curried function, this is solved later) . so when the element is clicked, the showi function is called which returns the show function that will evaluate with the i from the for loop.  Currying in general lets you save and pass around functions that have already been “evaluated” for their first n arguments.  Another quick example:

function add (a, b) {
  return a + b;
}

var addthree = add(3);
var sum = addthree(2);

so the value of “sum” would be 5 in this hypothetical language with currying.

So currying doesn’t exist in the core JavaScript but several libraries have implemented their own versions.  I ended up using the one from the Prototype library.  After you place this in your code, any function can be curried:

Function.prototype.curry = function() {
  var method = this, args = Array.prototype.slice.call(arguments);
  return function() {
    return method.apply(this, args.concat(Array.prototype.slice.call(arguments)));
  }
};

If you know that Array.prototype.slice.call(arguments) just returns the arguments as an array, this is really pretty simple.  Going back to the adding example:

function add(a, b) {
  return a + b;
}

var addthree = add.curry(3);
var sum = addthree(2);

in this case, our call to add.curry(3) is essentially returning this:

function() {
    return add.apply(this, [3].concat(Array.prototype.slice.call(arguments)));
  }

and calling addthree essentially does this:

add.apply(addthree, [3, Array.prototype.slice.call(arguments))]);

which will call the add function with the saved 3 and the new arguments  (2), reducing to a call of add(3, 2), which is exactly what we want! This is just on-the-fly storage in closures, but it achieves our desired result in a clean way.

Note: if you want to use a different scope (for example, if your curried function is a member function that uses ‘this’) just modify the curry to take in the scope as the first argument:

Function.prototype.curry = function() {
  var method = this, args = Array.prototype.slice.call(arguments),
  scope = args.shift();
  return function() {
   return method.apply(scope, args.concat(Array.prototype.slice.call(arguments)));
 }
};

Running Mochitests on the N800

For the past month or so I’ve been running the mochitest system for Firefox on builds of Fennec (code name of Firefox for mobile project). The mochitest system was written nicely enough to make this transition pretty smooth, requiring just one extra command line argument to get them running on Linux desktop builds (Mac builds force some hacking of the test system). Here are the instructions for building Fennec with tests and the tracking bug for the failures.

Running the same tests on a Nokia N800 device is a bit more troublesome. The memory usage for Fennec hovers right around the 128 MB the device normally has (there is some cool work going on right now to detect low memory and disable features based on this). Top that off with a small test server and mad Javascript libraries and you get a crashing browser.

The mochitest system is a python script that 1) spawns an HTTP server to serve the test files and 2) launches the browser with a fresh profile and special preferences and privileges. It points the browser to a specialized index page with a listing of the test files. Basically, the mochitest system is a webpage (test harness) that loads other webpages (tests) into an iframe one-by-one. These webpages go through different actions, popping up windows, ensuring certain handlers fire, etc. using assertions to communicate with the test harness. when all this is done and the page finishes loading, the main page gets the results of the tests and loads the next page into the iframe (unless you specify that the harness wait for you to signal that the test is finished) . There are thousands of these test webpages in the tree, each of which lives in the same directory as the code it is testing. When Firefox is built, these files are picked up and put in a directory structure where the testing code lives. You can run the entire tree of tests or just one folder.

Running the whole suite at once on the device is not possible right now. As a kind of work-around, I wrote a script to run the entire suite in chunks of small directories. It runs the tests for one directory, logs the results, then kills the browser and moves on to the next one, Finally coalescing the log files into one big log file at the end. This is necessary because some directories use of too much memory and crash the browser or reboot the phone, and others have tests that cause the test system to lose focus on the main test page and thus hang forever. You can kill the script and when it’s run again it will skip the directories that have already been run.

The mochitest system is an important part of keeping Firefox bug-free. When a test case is first written it’s used to verify that a certain feature works as it should or to show others how a bug plays out, but once it’s in the tree it becomes a regression test. The mochitests are run every time the Firefox trunk is built, so as soon as something regresses a bug, we know about it. We need this for Fennec. Regular builds of Fennec are starting to be set up, so hopefully this regression testing will follow behind closely.

I was in particular interested in what tests failed on the phone versus the desktop build and I’ll be analyzing this soon, probably in the tracking bug. Next up: running the chrome and browser-chrome mochitests.

note: the script is my first python script, so I probably wrote it all crappy and perl-like, let me know if you have any suggestions.