Thursday, December 12, 2013

C# Puzzle No.23 (intermediate)

Closures are interesting and helpful. In short, closure is a function that can be exposed to the outside world that captures part of its external environment, even though the environment could be private to outside world.

This puzzle involves following short snippet inspired by the Javascript: Definitive Guide book

// create array of 10 functions
static Func<int>[] constfuncs()
{
    Func<int>[] funcs = new Func<int>[10];
 
    for ( var i = 0; i < 10; i++ )
    {
        funcs[i] = () => i;
    }
 
    return funcs;
}
 
...
 
var funcs = constfuncs();
for ( int i = 0; i < 10; i++ )
    Console.WriteLine( funcs[i]() );
 
// output:
// 10
// 10
// ...
// 10

Side note: closures in Javascript work very similar and the output of corresponding Javascript snippet would be the same

function constfuncs() {
  var funcs = [];
  for(var i = 0; i < 10; i++)
  {
    funcs[i] = function() { return i; };
  }
  return funcs;
}
 
var funcs = constfuncs();
for ( var i = 0; i < 10; i++ )
    console.log( funcs[i]() );

End of side note

Your task here is not only to explain the behavior (easy part) but also correct the inner loop of the constfuncs method so that the code outputs

0
1
2
3
4
5
6
7
8
9

More specifically, you are allowed to modify only this line of code

funcs[i] = () => i;

You are free to propose a solution for the JavaScript version as well. The book doesn’t provide one, if you are interested.

5 comments:

Mojo said...

I'm interested to see some solutions to this. My first reaction would be to create a variable inside that inner scope which wouldn't be modified i.e.

var x = i;
funcs[i] = () => x;

But I'm not sure how to translate that into only that one line.

apl said...

For one, we can go lambda-happy:

funcs[i] = ((Func<int, Func<int>>)(j => () => j))(i);

Mojo said...

That's pretty much exactly where I was going, but it seemed like there must be a nicer way to wrap that into a closure.

Wiktor Zychla said...

@Mojo: That's exactly the solution I have in my mind. It does the trick as the inner delegate is returned from an auxiliary method that accepts i as a parameter which effectively stops it from being caught inside the closure. The same solution fixes the javascript version but there is no need for explicit type there.

Szymon Malinowski said...

Very nice post :) But for me tip " you are allowed to modify only this line of code" is a little bit misleading. It forbids declaration of new variable. So I found same solution as @apl. It looks bad in both languages, but works :)

funcs[i] = function(a) { return function() { return a; } }(i);