5

I read this question(What is the scope of a lambda variable in C#?)

But it is about Lambda variable scope inside LINQ Query.

Now to my question

Lets say I have a very simple LINQ query.

var Foo = FoobBar.Select(x => x);
var x = somefunction();

Compiler says : A local variable 'x' cannot be declared in this scope because it would give a different meaning to 'x', which is already used in a 'child' scope to denote something else.

Why is that so? Shouldn't Lambda variable cease to exist when LINQ query ends?

EDIT: After reading answers i came to conclusion that its the outside x (returned from function) whose scope extends inside LINQ Query.

Community
  • 1
  • 1
Nikhil Agrawal
  • 47,018
  • 22
  • 121
  • 208
  • 1
    After reading all answers i came to the conclusion that its the other way round. the scope of outside variable exists inside LINQ query. – Nikhil Agrawal May 23 '12 at 07:35
  • 1
    And the other way around too ;-) A language would not be refactoring-friendly if it allowed the code to compile just because the conflicting variable(`var x = somefunction();`) is at the second line, and then when you move the second line on first line, much to your chagrin, it would not compile anymore. C# does a pre-emptive mechanism, it doesn't allow `var x = someFunction()` to compile even it's on second line, as you might re-factor your code anytime and put it on first line later on. We are living on an age that a refactoring-amenable code is the norm – Michael Buen May 23 '12 at 08:13

5 Answers5

9

It's not about LINQ it's about child scopes.

For example:

foreach (var bar in FooBar.Bars)
        {
            var x = FooBar.GetFoo();
        }
var x = new Foo();

produces exactly the same error message from compiler.

To fix that you just have to place variables in different (non-nesting) scopes. For example:

foreach (var bar in FooBar.Bars)
        {
            var x = FooBar.GetBar();
        }
{
    var x = new Foo();
}
default locale
  • 13,035
  • 13
  • 56
  • 62
4

Lets look carefully,

var Foo = FoobBar.Select(x => x);

true the scope of x ends in the expression

var x = somefunction()

Now this is interesting, this is scoped for the entire method which holds the lamda expression too, so the compiler cannot distinguish since the scope of the latter overlaps the former. and very informative message too give a different meaning to 'x', which is already used in a 'child' scope (Select as in your case)

Similar scope question

maybe you can include braces around the other so that it's scope is defined

{
var x = somefunction()
}
Community
  • 1
  • 1
V4Vendetta
  • 37,194
  • 9
  • 78
  • 82
2

Think if C# would allow those two variables to exist on same scope level, this will not be possible:

static void test() {

    Action<int> x = (z) => {
        Console.WriteLine(z);               
    };


    int[] i = { 5,2,0,1,3,1,4 };

    var kyrie = i.Select (x => x);

}

How you would say to C# that you wanted to assign the Action delegate named x to kyrie variable; or the vice versa, how you would say to C# you wanted to use the integer projection itself? How C# would resolve that?

And C# scoping resolution is very consistent whether you declare it before the other variable or after the other variables, they are the same. e.g. http://www.anicehumble.com/2012/05/java-said-c-said-scope-consistency.html

To disambiguate those scenario, C# doesn't allow you to compile a program that have variable names that exists on same level

It's all about expressing your intent to the compiler in a non-ambiguous way. And C# did a good job on that regard

Michael Buen
  • 38,643
  • 9
  • 94
  • 118
1

It's not clear (to the compiler) which 'x' you mean by the second 'x' (after the =>).

What if you wrote this:

var Foo = FoobBar.Select(y => x);
var x = somefunction();

then that x in the lambda would clash with the 'somefunction' result.

Hans Kesting
  • 38,117
  • 9
  • 79
  • 111
1

You can't declare two variables with the same name in the same scope.

"Same scope" meaning they either are both inside the current scope

void method()
{
    int a;
    int a; //wrong!
}

or one is in the current and the other is in a child scope.

void method()
{
    int a;
    for(;;)
    {
        int a; //wrong again!
    }
}

This is by design and holds for any variable, from ints to lambda references.

Alex
  • 23,004
  • 4
  • 39
  • 73