Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lambda capture parameter provoking ambiguity

Tags:

c#

lambda

I just bumped into a really strange C# behavior, and I’d be glad if someone could explain it to me.

Say, I have the following class:

class Program
{
    static int len = 1;
    static void Main(string[] args)
    {
        Func<double, double> call = len => 1;
        len = 1; // error: 'len' conflicts with the declaration 'csutils.Program.len'
        Program.len = 1; // ok
    }
}

As I get it, in the line of commentary I have the following objects in my field of view: len variable and call. Inside of lambda, I have local parameter len and Program.len variable.

However, after declaring such lambda, I cannot use len variable in the scope of Main method anymore. I have to either refer to it as to Program.len either rewrite lambda to be anyOtherNameBesidesLen => 1.

Why is it happening? Is this correct behavior of language, or I’ve encountered a bug in the language? If this is correct behavior, how is it justified by the language architecture? Why is it okay for lambda capture variable to mess with code outside lambda?

Edit: Alessandro D'Andria has got quite nice examples (number 1 and 2 in his comment).

edit2: This code (equal to the one I wrote at the beginning) is illegal:

class Program
{
    static int len = 0;
    static void Main(string[] args)
    {
        {
            int len = 1;
        }
        int x = len;
    }
}

This code however, despite having exactly the same scope structure, is perfectly legal:

class Other
{
    static int len = 0;
    class Nested
    {
        static void foo()
        {
            int len = 1;
        }
        static int x = len;
    }
}
like image 772
Dantragof Avatar asked Mar 15 '14 18:03

Dantragof


1 Answers

As far as I can see, it is correct to emit a compile-time error in this case because it is not permissible to use len in a child scope (namely the parameter of the anonymous function (lambda)) when the same symbol len without qualification is used (for something else) in a containing scope within the same method.

However, the error text is confusing.

If you change to:

static int len = 1;
static void Main(string[] args)
{
    len = 1;
    Func<double, double> call = len => 1;  // error CS0136: A local variable named 'len' cannot be declared in this scope because it would give a different meaning to 'len', which is already used in a 'parent or current' scope to denote something else
}

the error text is better.


Some other examples:

static int len = 1;
static void Main()
{
    var len = 3.14; // OK, can hide field

    Console.WriteLine(len); // OK, 'len' refers to local variable

    Console.WriteLine(Program.len); // OK, hidden field can still be accessed, with proper qualification
}

The above example shows that it is fine to hide a field with an identically named local variable (or method parameter) as long as the field is always accessed with qualification (after a . member access operator).

static int len = 1;
static void Main()
{
    if (DateTime.Today.DayOfWeek == DayOfWeek.Saturday)
    {
        var len = 3.14;

        Console.WriteLine(len);
    }

    Console.WriteLine(len); // error CS0135: 'len' conflicts with the declaration 'csutils.Program.len'
}

This shows that it is not possible to hide len in a child scope when you try to use the field len in the parent scope. Again the error text can be criticized.

static int len = 1;
static void Main()
{
    Console.WriteLine(len);

    if (DateTime.Today.DayOfWeek == DayOfWeek.Saturday)
    {
        var len = 3.14;  // error CS0136: A local variable named 'len' cannot be declared in this scope because it would give a different meaning to 'len', which is already used in a 'parent or current' scope to denote something else

        Console.WriteLine(len);
    }
}

You see the analogy.


Of course these issues have been mentioned many times before here on SO, an example being Why can't a duplicate variable name be declared in a nested local scope?

like image 85
Jeppe Stig Nielsen Avatar answered Nov 16 '22 07:11

Jeppe Stig Nielsen