6

I have following code snippet in c#

static void Main()
{
    var numbers = new[] { 1, 2, 3, 4, 5, 6 };

    var ngt5 = numbers.Where(n => n > 5);

    var n = ngt5.First().ToString();

    Console.WriteLine(n, numbers);
}

When I am compiling the above code I am getting following error

A local variable named 'n' cannot be declared in this scope

santosh singh
  • 27,666
  • 26
  • 83
  • 129

2 Answers2

17

Your problem is here:

// Within your lambda you have an 'n'.
var ngt5 = numbers.Where(n => n > 5);

// And within the outer scope you also have an 'n'.
var n = ngt5.First().ToString();

To understand why this is a problem, consider the following code:

int n = 1000;
var evens = Enumerable.Range(1, 1000).Where(n => n % 2 == 0);

The expression n % 2 == 0 above is ambiguous: which n are we talking about? If we're talking about the outer n, then n % 2 == 0 is always true since n is just 1000 (and therefore evens will comprise all numbers from 1 to 1000). On the other hand, if we're talking about the inner n, then n % 2 == 0 will only hold true for even values of n (and evens will be 2, 4, 6, ... 1000).

The important point to realize is that variables declared outside the lambda are accessible from within the lambda's scope.

int n = 0;
Action incrementN = () => n++; // accessing an outer variable
incrementN();
Console.WriteLine(n); // outputs '1'

This is why the ambiguity exists, and why it is therefore not allowed.


The solution is simply to pick a different variable name for your lambda; e.g.:

var ngt5 = numbers.Where(x => x > 5);
Dan Tao
  • 125,917
  • 54
  • 300
  • 447
  • @Dan:you mean lambda variable is global? – santosh singh May 27 '11 at 17:35
  • 1
    @Dan:sorry for the stupid question...can we say that this is c# bug? – santosh singh May 27 '11 at 17:44
  • 1
    @geek: I wouldn't agree with that. What would you say is "wrong" about this behavior? From my perspective, it seems the compiler is preventing you from writing ambiguous code, which is a good thing. – Dan Tao May 27 '11 at 17:46
  • @Dan:thank you very very very very very very very much for clarifying my doubt...:) – santosh singh May 27 '11 at 17:48
  • JavaScript allows this ambiguity, which allows to write closures without any limit. By imposing this limit C# does not allow to use closures as first class functions unlike JavaScript. – alpav Feb 27 '13 at 18:39
0

Your problem is that you assume that closures are first class functions in C#, which is not the case and I wish it was the case.

You can't treat scope of C# closure as isolated function scope.

You can't return complicated Linq expression outside of current scope.

JavaScript allows this ambiguity, which allows to write closures without any limit, which makes closures first class functions of JavaScript.

alpav
  • 2,972
  • 3
  • 37
  • 47