Jason Watts
Jason Watts

Reputation: 1040

Closures for anonymous methods in C# 3.0

Why do closures exist for anonymous methods? Why not just pass state into the method without the overhead of a new class being generated with the closure variables being copied in? Isn't this just a throwback to "making everything global?"

Someone talk me down, I feel like i'm missing something here...

Upvotes: 2

Views: 1380

Answers (6)

Ray
Ray

Reputation: 3109

Some methods require a specific signature. For example:

public void set_name_on_click(string name)
{
    button.Click += (s,e) => { button.Text = name; };
}

A full closure solves this very neatly. You really don't want to mess with the anonymous methods signature.

Upvotes: 0

Marc Gravell
Marc Gravell

Reputation: 1062865

Purely, convenience... you don't know how much state you are going to need when defining, for example, a Predicate<T> - consider:

List<int> data = new List<int> {1,2,3,4,5,6,7,8,9,10};
int min = int.Parse(Console.ReadLine()), max = int.Parse(Console.ReadLine());
List<int> filtered = data.FindAll(i => i >= min && i <= max);

here we've passed two additional bits of state into Predicate<T> (min and max) - but we can't define List<T>.FindAll(Predicate<T>) to know about that, as that is a caller detail.

The alternative is to write the classes ourselves, but that is hard, even if we are lazy:

class Finder {
    public int min, max;
    public bool CheckItem(int i) { return i >= min && i <= max;}
}
...
Finder finder = new Finder();
finder.min = int.Parse(Console.ReadLine());
finder.max = int.Parse(Console.ReadLine());
List<int> filtered = data.FindAll(finder.CheckItem);

I don't know about you, but I prefer the version with the closure... especially when you consider how complex it gets when you have multiple contextual levels. I want the compiler to worry about it.

Consider also how often you use such constructs, especially for things like LINQ: you wouldn't want to have to do it any other way...

Upvotes: 8

Jonathan Allen
Jonathan Allen

Reputation: 70307

Because you take write this:

var divsor = [...]
for(int x = 0; x < 10000000; x++){
     source[x] = source[x] / divsor         
}

And easily turn it into this

var divsor = [...]
Parallel.For(int x = 0; x < 10000000; x++, ()=> {
     source[x] = source[x] / divsor         
})

Upvotes: 0

Noldorin
Noldorin

Reputation: 147340

The overhead of creating a new class probably isn't something to worry about. It's just a convenient way for the CLR to make bound variables (those captured by the closure) available on the heap. They are still only accessible within the scope of the closure, so they're at all not "global" in the traditional sense.

I believe the reason for their existence is mainly convenience for the programmer. In fact, it's purely that as far as I'm concerned. You could emulate the behaviour of a closure pretty well before they existed in C#, but you don't get any of the simplicity and syntactical sugar that C# 3.0 offers. The entire point about closures is that you don't need to pass the variables in the parent scope to the function, because they're automatically bound. It's much easier and cleaner for the programer to work with, really, if you consider that the alternative is true global variables.

Upvotes: 3

Joel Martinez
Joel Martinez

Reputation: 47749

At least one thought is that closures exist in other languages such as javascript. So they probably included closures to be in line with people's prior experience with anonymous methods.

Upvotes: 0

eulerfx
eulerfx

Reputation: 37719

Because the CLR takes care of it, the easiest way to "pass state into the method" is to auto-generate a class, which encapsulates that state.

Upvotes: -1

Related Questions