Tuesday, October 17, 2006

Introduction to Closures

Closures (also referred to as Blocks) are supported in many functional programming languages like SmallTalk, Lisp, Javascript..the newest ones being C# 2.0 and Ruby. So what are closures?

A closure is a block of code that can be passed as an argument to another method. At a most basic level, they are functions defined inside a scope of some sort. You can then pass the function around and call it whenever, and the function continues to execute as if it were still inside the scope it was defined in.

Example 1: Assume that the Remove.invoke method takes in two parameters: the service to call, and the callback function to invoke when the service call finishes.

function getSomethingById(id) {
Remote.invoke("http://domain.com/neat_service/" + id, function(response) {
recordSomethingById(id, response);
});
}

What's going to happen is that when the request finishes, the server's response is going to be passed as an argument to the callback function. This callback function is going to be invoked LONG after this bit of code actually runs to completion (because the remoting request is asynchronous). But still, as you observe, the callback function can use variables that are defined outside the callback, but inside the outer function (e.g. the id parameter), even though the outer function has long since returned. That forms the essence of a closure.

Example 2:
function counter(num)
{
var enclosedVar = num;
return function() {enclosedVar++};
}

Here - as you observe the inner anonymous function defines a closure over the local variable "enclosedVar". The function "counter" returns a reference to this closure, which can then later be executed at any point of time. Note that the local variable "enclosedVar" does not go out of scope, as far as the closure is concerned.

We can put this closure to use as follows:

var myIncFunction1 = counter(5);
var myIncFunction2 = counter(10);

The function references returned by the counter method can be stored in a variable and invoked as follows:

print(myIncFunction1()); // prints value 5
print(myIncFunction1()); // prints value 6
print(myIncFunction2()); // prints value 10
print(myIncFunction2()); // prints value 11

Note that we will get the output as mentioned above, because the two separate calls to counter method actually created two independent closures.

Closures as inside-out objects:
Rightfully referred to as that. Objects are data that have sub-routines attached to them, where as, closures are sub-routines with some data associated with them.

Passing code around, instead of data:
If I have to sort a collection of things, where the collection can possibly contain different types of data, I will have to write separate sort methods in order to handle the various types of data. However, with closures and the ability to pass code / functions as arguments, I can write one single "sort" method that accepts the collection as one parameter and the code to do the actual comparison as the second parameter. Found one code snippet that shows how this can be done:

function sort(collection, comparator) {
var n = collection.length;
for (var i=0; i < n - 1; i++) {
for (var j=0; j < n - i - 1; j++)
if (comparator(a[j+1], a[j])) {
swap(collection, j, j + 1);
}
}
}
}
c = [
{name: "barney", height: 195, weight: 80},
{name: "heather", height: 182, weight: undefined},
{name: "jerry", height: 185, weight: 81}
]c_by_height = sort(c, function(a, b) {
return a.height < b.height;
});
c_by_name_reverse = sort(c, function(a, b) {
return a.name > b.name;
});

So - here the sort method is pretty much generic, we can write different comparators to handle the actual comparison and pass those comparators around.

One good link that gives examples of closures in Javascript: http://blog.morrisjohns.com/javascript_closures_for_dummies

2 comments:

Siddhesh said...

Petty heavy duty stuff! I like the idea in the comparator example, but I think I will need to read this a couple times more when I have a clearer head to get the real gist!

Jatinder Singh said...

Methods in ruby extensively use blocks for the 2nd usage i.e. passing code to the methods, it results in generic methods as you have illustrated.
Methods of most of the built-in classes of ruby accept blocks.

I feel blocks can also be used to achieve aspect oriented behavior. For that all the methods have to accept a block and they should execute the block code as first statement of the method.
To deal with logging, while calling these methods we can pass a block having code to log messages to the log.