Practical Closures

posted Jan 02, 2007
in Programming

The problem I see with most introduction to closures is they choose examples that can be done easily with a standard for loop, or some other standard construct, leading a student to ask (with great justification!) what the point is and why (s)he should bother. In my opinion, the best place to start understanding them practically is to look at their ability to decouple logic, because there they have benefits that are difficult or even impossible to replicate without them.

So despite the huge amount of verbiage on the net about closures, I thought I'd take another crack at explaining it with examples that actually do something that is much harder to do without closures.


What is a "closure"? Rather than dive into the theory, let's give it this simple definition: A closure is a function that you can pass around that retains the same "environment" as the one it had when it was created. One of the problems with closures is that the definitions are only comprehensible once you already understand them, so let's learn by example. After that, you'll understand the definition.

For concreteness, I'm going to use Javascript as a sort of lowest-common-denominator language that has closures, and also has a shell everybody can use. You can paste this code there as we go along and play with these functions directly. (I've included "alert" calls so you get to see something; you may want to simplify away the HTML, but I wanted to show you a minimally useful example that actually did something.)

A common thing to do in all kinds of programming is to render a set of objects somehow, be it into HTML on the web or a series of controls in a GUI. It is often the case that you will have multiple different renderings that have a lot in common with each other, such as "SQL search results" or "A series of drag-and-droppable objects" and it would be nice to factor out the portions of that rendering that stay the same, no matter what the specific objects being rendered are. Again for concreteness and a lowest common denominator, consider building a simple HTML table for some set of objects.

It is easy to build a function that takes one particular object in, and returns its HTML representation:

function renderIntAsHTML (i) { 
  return "This int is <b>" + i + "</b>"; 
}

(And let's ignore non-closure issues like the potential evilness of constructing HTML via string concatenation, escaping nightmares, performance, etc. KISS. But please don't do it this way for real!)

It is also easy to build a function that takes in an array of objects and renders a table from them:

function renderObjectsInTable (array) {
  var table = "<table>";
  for (var idx in array) {
    var object = array[idx];
    table += "<tr><td>" + object + "</td></tr>";
  }
  table += "</table>";
  return table;
}

But this uses the implicit stringification of Javascript, and it's pure luck if that's actually the rendering you want. There are multiple ways to handle this, but one good way is to pass in a function to use for the rendering:

function renderObjectsInTable (array, renderer) {
  var table = "<table>";
  for (var idx in array) {
    var object = array[idx];
    table += "<tr><td>" + renderer(object) + "</td></tr>";
  }
  table += "</table>";
  return table;
}

Now we can pass in the renderIntAsHTML function:

alert(renderObjectsInTable([1,2,3], renderIntAsHTML))

And now these two pieces have been cleanly put together, and each of them is still useful outside of this context.

But this is not actually passing a "closure". What makes a "closure" different than a function is the reference to variables/bindings/[language-appropriate name here] that are in the environment that defined the function, not just the arguments. renderIntAsHTML uses only the parameters passed in to it so it is still a "function", and this is just passing a function to another function. This is useful, but perfectly doable with interfaces in pure OO, albeit a little more klutzy, or with traditional C(++)-style function pointers. Closures get fun when you want to do something that want to use (or possibly modify) other state, without requiring the target function to understand your state.

Let's suppose instead that we want to show a running total of the ints, in addition to the int itself. We can do it this way:

function intTableWithTotals (intArray) {
  var total = 0;
  var renderInt = function (i) {
    total += i;
    return "Int: " + i + ", running total: " + total;
  };
  return renderObjectsInTable(intArray, renderInt);
}

Notice the total variable; it is defined outside of the definition of renderInt, but is used by renderInt. Thus, this is an actual closure. The last bolded line shows where we pass this closure into the original renderObjectsInTables function.

If we now call it:

alert(intTableWithTotals([1,2,3]))

We get a table with the running totals in there, not just the ints themselves. Try it by pasting the code into a Javascript Shell.

No, seriously, go paste the function definitions in. I'm not showing the output here just so that you will go do it and not just read the output in a web page.

Here's the part that should get you excited: We didn't have to modify renderObjectsInTable for this. And perhaps even more importantly, whoever wrote renderObjectsInTable in the first place didn't have to explicitly plan for the case where we wanted to do something like that, which is where strongly-typed pure-OO starts to choke.

There are pure-OO ways to try to do some of this; one way would be to create a Render interface on the target objects, and require everything passed into a renderObjectsInTable-sort of function to support this interface. But your renderer would still lack context, which means both that it could not do any sort of aggregation of data, and that the renderer could only render data in the object, not using anything from the environment itself. You can of course eventually come up with a class structure that will implement everything a closure could do, but it would be quite complicated.

(It should also be pointed out that this is so easy that I typed all of these examples correctly the first time before I tested them. It is unlikely that any OO-based solution is going to be that simple.)

Worst of all, you'd still have to convince external vendors to use this complicated class structure; if they don't start with it, you're out of luck. Taking closures is easy enough to do that libraries and frameworks actually do it sometimes. (Not often enough!... but sometimes.)

Using a closure is an easy way for an API to provide a critical piece of functionality, while not constraining the context of the caller, and cleanly allowing a lot of extension. I've written more complicated and complete versions of this sort of rendering code several times now in several contexts, and the closure approach offers a cleanliness that "pure OO" could not match.

Now, this is still a trivial example, but to replicate the full functionality of the closure here using other non-closure functionality is going to involve a lot more code; you can't just swap out this closure for a for loop. The pattern of interaction here is something that can only be replicated with great difficulty and fragility with pure-OO only.

This is a broadly-applicable and useful use-case that can give you a reason to work with closures. From this use, you can gain a more practical and gut understanding of how they are useful, and then move on to the more theoretical or obscure uses; I'm not claiming this is all they are about.

 

Site Links

 

RSS
All Posts

 

Blogroll