Monday, May 01, 2006

Close Yours!

Since I've read about programming languages on and off for 15 years, I've heard of the term closures, but never quite understood it. It's odd that I would learn about this at a No Fluff Just Stuff tour as part of the Northern Virginia Software Symposium.

This is a tour of speakers that talk about topics related to Java and the open source community. The speakers talk about topics ranging from new features in Java, server side technology, agile development, new languages, Ruby, Ruby on Rails, Ajax, and some topics like semantic web and rules engines that are somewhat more AI-ish.

I was listening to Glenn Vanderburg giving two talks on JavaScript. He mentioned closures, and was describing what they were (and how they appear in Java). After that explanation, I think I have it.

Basically, in OO terms, a closure is an object that represents a function whose free variables have been captured at the time the function was called. Let me illustrate a simple example.


function foo(y) {
return function(x) {
return x + y;
}
}

Let's look at what's being returned. It's a function (or function object). In a functional language (i.e., a language that has functions as first-class citizens, and that generally does not allow for assignment, languages like ML, Haskell, O'Caml, etc.), I'd use the word lambda which refers to an anonymous function.

Before I continue with my explanation of closures, think of the following. What is a variable? It's a name for something. In Java, I can declare a variable of a certain type and assign it a value. For example, I can declare the variable x and then assign it to a value like 3.

What if I wanted to declare a variable and have its type be a function? Does that seem weird? For example, I might want to have a function call addTen which takes a value as argument and adds 10 to that and returns it. Can I have a variable called addTen? And what should I assign it to?

I want to assign it to a value. For example, I just assigned 3 (an int value) to x. I want to assign a function value to a variable. What is a function value? It's a function without a name. I just happened to call it function, but that doesn't mean you can call that function by saying function(3). It's not the name of a function, but a keyword that says "I'm defining a function value".

Now, when I write something like:


function add(x, y) {
return x + y;
}

this is the equivalent of saying

var add = function(x, y) { return x + y; }

meaning assign the variable add to an anonymous function that takes two variables. That function returns the sum of x and y.

Notice the right hand side starts with function but is not followed by a function name.

Thus, add is a variable that represents a function and I can call it like: add(3, 5).

I could assign add to other functions, say one that multiplies or one that divides. That wouldn't be good naming practice, but it could be done.

So, let's go back to the example I started off with:

function foo(y) {
return
function(x) {
return x + y;
}
}

What does this function return? An anonymous function (value) which sums x and y. This function takes one variable, x. What about y?

Where does y come from?

This is where the closure comes from. y is a free variable within the function. It's not a parameter in the function. It's not a local variable within the function. However, there is a y defined in the outer scope.

Suppose you call foo(7). At the time you call that function, the parameter y gets bound to 7. In the return function, that y gets bound or closed. It "remembers" the value 7 (or really, the environment at the time it was called).

Thus, if you have foo(3), you create a function that adds 3 as a result. If you call foo(10), this adds 10 to the value.

Thus,

var adds3 = foo(3);
print adds3(100); // Prints 103

var adds10 = foo(10);
print adds10(100); // Prints 110

Thus, a closure captures the value of free variables at the time the function gets constructed, and allows us to make new functions without having to recompile new code. Basically, we get flexibility on the unbound variables (variables that are neither local variables in the function, nor parameters passed in) to customize a function.

And that's a closure.

No comments: