This question came up at the last Brighton ALT.NET Beers. It proved almost impossible to discuss in words without seeing some code, so here’s my attempt to explain closures in C#. Wikipedia says:
In computer science, a closure (also lexical closure, function closure or function value) is a function together with a referencing environment for the nonlocal names (free variables) of that function. Such a function is said to be "closed over" its free variables. The referencing environment binds the nonlocal names to the corresponding variables in scope at the time the closure is created, additionally extending their lifetime to at least as long as the lifetime of the closure itself.
So a closure is a function that ‘captures’ or ‘closes over’ variables that it references from the scope in which it was created. Yes, hard to picture, but actually much easier to understand when you see some code.
var x = 1;
Action action = () =>
{
var y = 2;
var result = x + y;
Console.Out.WriteLine("result = {0}", result);
};
action();
Here we first define a variable ‘x’ with a value of 1. We then define an anonymous function delegate (a lambda expression) of type Action. Action takes no parameters and returns no result, but if you look at the definition of ‘action’, you can see that ‘x’ is used. It is ‘captured’ or ‘closed over’ and automatically added to action’s environment.
When we execute action it prints out the expected result. Note that the original ‘x’ can be out of scope by the time we execute action and it will still work.
It’s interesting to look at ‘action’ in the debugger. We can see that the C# compiler has created a Target class for us and populated it with x:
Closures (along with higher order functions) are incredibly useful. If you’ve ever done any serious Javascript programming you’ll know that they can be used to replace much of the functionality of object oriented languages like C#. I wrote an example playing with this idea in C# a while back.
As usual, John Skeet covers closures in far more detail. Check this chapter from C# in Depth for more information, including the common pitfalls you can run into.
8 comments:
I'm not convinced this is correct. If I run the following through LinqPad it gives result = 12, whereas I suspect the result you expect is 3 (apologies re formatting):
var x = 1;
Action action = () =>
{
var y = 2;
var result = x + y;
Console.Out.WriteLine("result = {0}", result);
};
x = 10;
action();
I think this is the closure you're looking for, which "closes" the scope and returns a result of 3:
var x = 1;
Func CreateAdder = z => () =>
{
var y = 2;
var result = z + y;
Console.Out.WriteLine("result = {0}", result);
};
var action = CreateAdder(x);
x = 10;
action();
Sorry, the Func declaration is incorrect because the angle brackets were stripped out, should have type parameters of int, Action.
Hi David,
What do you mean 'not convinced this is correct'? Are not convinced that my code example does what I say it does? Or are you not convinced that what I'm showing you is a closure?
In your first example, 12 is exactly the result you would expect. The closure has a reference to x, when x is changed, the result changes too. It's one of the common gotchas of using closures, and it's especially common for people to come unstuck when referencing some loop variable in a closure.
I guess that's the point you wanted to make?
I don't think your example is a closure but I'm happy to be educated otherwise. I tend to fall back on my knowledge of closures in javascript for this. Consider (ref):
var funcs = {};
for (var i = 0; i < 3; i++) { // create 3 functions
funcs[i] = function() { // and store them in funcs
console.log("My value: " + i); // each should log value
};
}
for (var j = 0; j < 3; j++) {
funcs[j](); // and now run each one
}
It outputs this:
My value: 3
My value: 3
My value: 3
Want it to output:
My value: 0
My value: 1
My value: 2
This is a fairly common mistake in javascript and crops up e.g. when trying to assign eventhandlers in a loop. One resolution is to introduce an intermediate function to capture the loop variable which will give the desired output:
var funcs = {};
for (var i = 0; i < 3; i++) { /* let's create 3 functions */
funcs[i] = function(k) { /* and store them in funcs */
return function() {
console.log("My value: " + k); /* each should log its value */
}
}(i);
}
for (var j = 0; j < 3; j++) {
funcs[j](); /* and now let's run each one to see */
}
Hi David,
"I don't think your example is a closure" - well we'll have to disagree then :)
Nice article, thanks.
I've written a bit more thorough one about Ruby blocks and closures
Ok, I see what you're saying. As long as action is in scope, then even if x is no longer in scope, by virtue of being captured by action it will remain accessible within action. In the example, without showing x going out of scope it wasn't obvious where the magic was happening. Jon Skeet has a good example of this over on SO.
omg you misspelled Jon Skeet's name ;)
Post a Comment