For some time now I've been using closures quite a bit in my Javascript, and I've been intrigued by the concept since I first encountered it (might have been in one of Sidharth's talks). I feel like exploring closures in a couple of other languages too.
Simply put, a closure is a function pointer which contains one or more references to some state (typically variables) contained outside the function definition itself. This combination of function + state can be looked at as a simple object. Thus a closure is an object which implements the "call" interface (the "()" operator) and refers to some external state variables while implementing that interface.
An example in Pythondef func(x):
y = 5
def closure():
return x + y
return closure
//let's instantiate and invoke the closure
closureFunc = func(5)
print closureFunc()
> python closure.py 10
Here, the function func() creates a closure by defining a function closure() which refers to an external variable "y", and returning a reference to that function. The invocation of the closure later, returns 10, since y=5 when the closure was defined.
A restriction of closures in Python is that you can modify the state of the enclosing scope only if they are global variables or instance variables of a class. This is because Python does not offer a way to refer to an enclosing context which is neither global state nor instance variable. Paul Prescod explains the issue on a newsgroup.
In Javascript, however, the enclosing context is looked up in a closure. So we can modify the value of "y" in the closure.
function func(x){
var y = 5;
function closure(){
var returnValue = x + y;
//let's change the value of "y" here
y = y + 1;
return returnValue;
}
return closure;
}
var closureFunc = func(5);
closureFunc()
10
//y is now 6. This is something you can't do in Python
closureFunc()
11
I don't see much need for changing the state in the enclosing context though. So in general you wouldn't miss it in Python.
One issue that crops up in closure creation is the binding of the referenced context variables. The variables are lexically scoped, but dynamically bound, i.e., the variables looked up are those declared in the enclosing scope of the closure, but the values of these variables are not necessarily the same as when the closure was created. They could have been changed by the time the closure is invoked.
Below I create a series of closures in a for-loop, each of which reference the loop index variable. You can see that all the closures get the final value of the index variable when invoked.
function func(){
var closures = new Array();
for(var i=0; i < 3; i++){
var newClosure = function(){
return i;
}
closures.push(newClosure);
}
return closures;
}
var closures = func();
closures.length;
3
closures[0]();
3
closures[1]();
3
closures[2]();
3
This is actually a useful feature, but a potential pitfall in cases like this.