Monday, December 21, 2009

So what are these closure thingys?

A couple of nights ago, I dreamed about closures. I was explaining them to my friend Michael. I think I did an OK job, but since Google still can't search my dreams (glare!), I thought I'd post something here.

What are closures?


Closures are a way to let a function have persistent, private variables - that is, variables that only one function knows about, where it can keep track of info from previous times that it was run.

Let's break this down.

Private variables


Giving a function a private variable is easy: just make a local variable inside it. For instance, in Javascript:

function annoyingAlert(){
   var x = "I'm private! ";
   x += "Nobody can see me outside this function.";
   alert(x);
   x = "Yep, still private.";
} 

Although x can't be changed from outside our function, it is very short-lived: each time the function finishes, x gets thrown away. When the function runs again, it is re-created. The second string it gets assigned will never be seen in the alert.

Persistent Variables


These are also pretty easy. Just make a... (sinister music) global variable.

nastyGlobalX = 1;
function annoyingAlert(){
   var alertString = "I can count! ";
   alertString += "I'm currently at " + nastyGlobalX;
   alert(alertString);
   nastyGlobalX++;
}


Now you've got persistence - each time you call annoyingAlert(), you'll get a new number. But since we're using a global variable, it could get changed by a different function. Our counting would be ruined!

Enter closures


This is where closures come in. They work like this:

1. Make an outer, "function maker" function.
2. Declare a local variable inside it.
3. Declare an inner function inside the outer one.
4. Use the outer function's variable inside the inner function.
5. Have the outer function return the inner function
6. Run the function, and assign its return value to a variable

For example:

function functionMaker(){
   var x = 1;
   function innerFunction(){
     alert(x);
     x++;
   }
   return innerFunction;
}

var counterFunction = functionMaker();
counterFunction();
counterFunction();

See! Magic!

Wait, you look confused. OK, let's back up.

A Closer Look


OK, look at the example above. What gets assigned to the variable called 'counterFunction?'

At first glance, you might say it's the functionMaker function. But it's not - we said 'functionMaker()', with parentheses, which means 'run that function and put its return value here.' When functionMaker runs, it ends by returning innerFuction. So counterFunction = innerFunction.

The magic happens at step 5. When functionMaker returns innerFunction, its life is over. Like a used tissue, it has served its purpose and will be thrown away. That includes any local variables that it contained.

But wait! Its innerFuction can't be thrown away, because we've assigned it to a variable, counterFunction. We still need it! And counterFunction() uses the local variable that functionMaker() declared (which was called 'x'). So that variable can't be thrown away either.

But where is that variable? It's in the twilight zone. From counterFunction()'s perspective, it was declared in the parent scope and persists from one run to the next, just as though it were a global variable.

But from any other function's perspective, it's a local variable, declared inside functionMaker(). They can't touch it or see it.

Yeeha! Now we've got a variable that's both private and persistent. It's a place for counterFunction to keep its record, safe from meddling and from garbage collection.

What's it good for?


But... so what? What can we do with that?

Well, a closure could be used to generate, for example, a function called newUserID(). Every time you call that function, you'd get a new ID. But in most situations, you'd want to take care of something like that in a database.

A closure would only help if you need a variable to stick around while your program is running, but no longer.

Next post, I'll show an example where that's exactly what you'd need.