views:

314

answers:

3

Inspired by this question I began wondering why the following examples are all illegal in c#:

VoidFunction t = delegate { int i = 0; };

int i = 1;

and

{
   int i = 0;
}

int i = 1;

I'm just wondering if anyone knew the exact reason why the language was designed this way? Is it to discourage bad programming practice, and if so why not just issue a warning?, for performance reasons (compiling and when running) or what is the reason?

+9  A: 

This behavior is covered in section 3 of the C# language specification. Here is the quote from the spec

Similarly, any expression that occurs as the body of an anonymous function in the form of a lambda-expression creates a declaration space which contains the parameters of the anonymous function. It is an error for two members of a local variable declaration space to have the same name. It is an error for the local variable declaration space of a block and a nested local variable declaration space to contain elements with the same name. Thus, within a nested declaration space it is not possible to declare a local variable or constant with the same name as a local variable or constant in an enclosing declaration space.

I think the easier way to read this is that for the purpose of variable declaration (and many other block related functions) a lambda/anonymous delegate block are treated no different than a normal block.

As to why the the language was designed this way the spec does not explicitly state. My opinion though is simplicity. If the code is treated as just another block then it makes code analysis routines easier. You can preserve all of your existing routines to analyze the block for semantical errors and name resolution. This is particularly important when you consider variable lifting. Lambdas will eventually be a different function but they still have access to all in scope variables at the declaration point.

JaredPar
It appears that the problem is that they make no distinction between scope before and after a decleration. This probably simplifies things quite a bit for the compiler vendor at the expense of burdening the programmer.
Anders Rune Jensen
@Anders, Yes but in this case there is a work around. Shipping is a constant pressure and when faced with a choice between a large work item to gain a small bit of functionality or small item which makes the lack of functionality explicit and can be reversed later, the small work item usually wins.
JaredPar
I don't see how this could be very hard to implement, at least not in the if case. Just use a stack and be done with it. It smells a lot either a bug or a measurement to prevent people from shooting themselves in the foot that took some nice functionality with it.
Anders Rune Jensen
+2  A: 

I think it is done this way so that the inner scope can access variables declared in the outer scope. If you were allowed to over-write variables existing in the outer scope, there may be confusion about what behavior was intended. So they may have decided to resolve the issue by preventing it from happening.

recursive
You are not overwriting. The declaration in the outer scope comes *after* the inner scope.
Anders Rune Jensen
A: 

I think it's this way to prevent devs from shooting themselves in the foot.

erikkallen
How many devs have guns? Maybe they should attend some target practise...might save a few feet.
Jeff Yates