Closures in C# can be evil

I had a problem with yield and closures. A friend Glenn Block gave me a good link on this. you can read it here >> http://codebetter.com/blogs/matthew.podwysocki/archive/2008/09/12/side-effects-and-functional-programming.aspx

here is an abstract from the blog about the problem. This can cause a lot of pain and that is why I am sharing it so that you do not fall in the same trap!

Closures and Lazy Evaluation

One last topic for this post revolves around variable instantiation around closures and what it means to you in regards to lazy evaluation.  Let’s look at a quick example of some of the issues you might face. 

C#

var contents = new List<Func<int>>();
var s = new StringBuilder();
for (var i = 4; i < 7; i++)
    contents.Add(() => i);
for (var k = 0; k < contents.Count; k++)
    s.Append(contents[k]());
Console.WriteLine(s);

What we might expect the results to be in this case would be 456.  But that’s not the case at all here.  In fact, the answer you will get is 777.  Why is that?  Well, it has to do with the way that the C# compiler creates a helper class to enable this closure.  If you’re like me and have Resharper, you’ll notice that it gives a warning about this with "Access to modified closure".  If we change this to give ourselves a local variable inside the loop closure construct to initialize the value properly.  If we do that and change our code, it will now look like this:

C#

var contents = new List<Func<int>>();
var s = new StringBuilder();
for (var i = 4; i < 7; i++)
{
var j = i;
    contents.Add(() => j);
}
for (var k = 0; k < contents.Count; k++)
    s.Append(contents[k]());
Console.WriteLine(s);

Jason Olson has a pretty good explanation in his post "Lambdas – Know Your Closures".

 

Hope it helps!

9 thoughts on “Closures in C# can be evil

  1. Pingback: Dew Drop – June 3, 2010 | Alvin Ashcraft's Morning Dew

  2. I understand the frustration, and the warnings are appropriate, but there’s a lot of things said here (including by commentors) that rub me wrong.

    “Closures in C# can be evil” I appreciate that this is the title, and as such is meant to grab attention, so it’s forgivable, but there’s no “evil” here. Rather, it’s a case of “with great power comes great responsibility”.

    The concerns here are not related to C#, either. Closures behave the same no matter the language.

    You need to understand closures. They aren’t just a snapshot of the current state. They more like references or aliases. If you have to references to the same class instance, you’re not surprised when modifying the object through one reference is visible through the second, and this is exactly what’s going on with closures.

    You think this can be difficult in .NET, you should have been working with me on a massive project I worked on that used XUL and JavaScript. 🙂

    I will say, however, that this topic is precisely why LINQ Rx scares me. With traditional LINQ it’s generally not too difficult to avoid using closures, or using them in careful and controlled situations. It seems to me that in Rx it’s going to be very difficult to do much of anything without using closures, and it could be much more difficult to reason about the usage of them. I feel the same about Rx as I do about threads… very powerful and important, but the average developer is going to screw things up every time they touch them.

  3. > Jason Olson has a pretty good explanation in his post “Lambdas – Know Your Closures”.

    The link at the bottom of the post doesn’t seem to work.

  4. Greetings I recently finished reading through your blog and also I’m very impressed. I truly do have a couple questions for you personally however. You think you’re thinking about doing a follow-up submitting about this? Will you be planning to keep bringing up-to-date at the same time?

  5. Pingback: Closures in C# « Rich Newman

  6. Pingback: » Azure table storage query returning data from wrong partition?

Leave a comment