tags:

views:

418

answers:

3

I've been reading this article about closures in which they say:

  • "all the plumbing is automatic"
  • the compiler "creates a wrapper class" and "extends the life of the variables"
  • "you can use local variables without worry"
  • the .NET compiler takes care of the plumbing for you, etc.

So I made an example based on their code and to me, it seems as though closures just act similarly to regular named methods which also "take care of the local variables without worry" and in which "all the plumbing is automatic".

Or what problem did this "wrapping of local variables" solve that makes closures so special / interesting / useful?

using System;
namespace TestingLambda2872
{
    class Program
    {
        static void Main(string[] args)
        {
            Func<int, int> AddToIt = AddToItClosure();

            Console.WriteLine("the result is {0}", AddToIt(3)); //returns 30
            Console.ReadLine();
        }

        public static Func<int, int> AddToItClosure()
        {
            int a = 27;
            Func<int, int> func = s => s + a;
            return func;
        }
    }
}

Answer

So the answer to this one is to read Jon Skeet's article on closures that Marc pointed out. This article not only shows the evolution leading up to lambda expressions in C# but also shows how closures are dealt with in Java, an excellent read for this topic.

+19  A: 

Your example isn't clear, and doesn't (IMO) show typical capture usage (the only thing captured is a, which is always 3, so not very interesting).

Consider this text-book example (a predicate):

List<Person> people = ...
string nameToFind = ...
Person found = people.Find(person => person.Name == nameToFind);

Now try it without a closure; you need to do a lot more work, even if we are lazy:

PersonFinder finder = new PersonFinder();
finder.nameToFind = ...
Person found = people.Find(finder.IsMatch);
...
class PersonFinder {
    public string nameToFind; // a public field to mirror the C# capture
    public bool IsMatch(Person person) {
        return person.Name == nameToFind;
    }
}

The capture approach extends further to lots of variables at different scopes - a lot of complexity that is hidden.

Other than the names, the above is an approximation of what the C# compiler does behind the scenes. Note that when additional scopes are involved we start chaining the different capture classes (i.e. inner scopes have a reference to the capture class of outer scopes). Quite complex.

Jon Skeet has a good article on this here, and more in his book.

Marc Gravell
(to the deleted question about making it `static`): No - because different threads might want to search for different names at the same time, or defer execution of the delegate.
Marc Gravell
+1 for the C# in Depth part on closures
Russ Cam
+1 for this sentence in the C# in Depth closures article: "closures allow you to encapsulate some behavior, pass it around like any other object, and still have access to the context in which they were first declared"
Edward Tanguay
Well, I can't take credit for what is in the article - you might want to drop Jon a +1 somewhere ;-p
Marc Gravell
it's an excellent article, shows in code the C# evolution from predicates (1) to anonymous methods (2) to lambda expressions (3) all the while showing the equivalent java code as well, I'll give Jon a couple points by buying his C# in Depth book ;-p
Edward Tanguay
A: 

The closure is a functionality of the Compiler. You don't see it, it just makes the code you write work.

Without it, the call to AddToIt(3) will fail, because the underlying lamda uses the local variable a = 27 in the scope of AddToItClusure(). This variable is does not exist when AddToIt is called.

But because of the Closure, a mechanism used by the compiler, the code works and you don't have to care about it.

Stefan Steinegger
+1  A: 

I think this article explains it better than the one you read:

http://srtsolutions.com/blogs/billwagner/archive/2008/01/22/looking-inside-c-closures.aspx

Gert M