Thursday, July 22, 2004

Another interesting discussion on MSDN Newsgroups:

The original question:

Hi,

   When I try and compile the a class containing the following method :

    public void doSomething() {
        for (int i=0; i<5; i++) {
            IList list = new ArrayList();
            Console.WriteLine( i / (list.Count) );
        }
        int i = 23;
        IList list = new ArrayList();
        Console.WriteLine( i / (list.Count) );
    }

I get the following errors :

D:\Forecaster\TestForecaster\TestBaseEntities.cs(402): A local variable
named 'i' cannot be declared in this scope because it would give a different
meaning to 'i', which is already used in a 'child' scope to denote something
else

D:\Forecaster\TestForecaster\TestBaseEntities.cs(402): The name 'i' does not
exist in the class or namespace 'ForestResearch.UnitTests.TestBaseEntities'

D:\Forecaster\TestForecaster\TestBaseEntities.cs(403): A local variable
named 'list' cannot be declared in this scope because it would give a
different meaning to 'list', which is already used in a 'child' scope to
denote something else

D:\Forecaster\TestForecaster\TestBaseEntities.cs(403): The name 'list' does
not exist in the class or namespace
'ForestResearch.UnitTests.TestBaseEntities'

The C# Language spec states :
  a.. The scope of a local variable declared in a for-initializer of a for
statement (§8.8.3) is the for-initializer, the for-condition, the
for-iterator, and the contained statement of the for statement.
If the put the statements following the for statement in an anonymous block
like this then the compiler is happy :

    public void doSomething() {
        for (int i=0; i<5; i++) {
            IList list = new ArrayList();
            Console.WriteLine( i / (list.Count) );
        }
        {
            int i = 23;
            IList list = new ArrayList();
            Console.WriteLine( i / (list.Count) );
        }
    }

Interestingly if I do the converse (i.e. put the for statement in an
anonymous block and DON'T put the statements following in an anonymous
block) then I get the same compiler errors!

I'm using Microsoft Visual Studio 2002.

Questions :

1. I would have thought that the scope of 'i' is the for initializer and for
statement so that this identifier could be used again as I have done above
in my first example ?

2. Likewise I would have thought that the scope of the variable 'list'
should just be the block in which it is declared and so could be used again
as I have done in my first example ?

3. Why does my second example produce no compiler errors ?


Thanks in advance,

Really interesting because you would expect the compiler to work without a problem. After some basic research, I found out that it is a compiler feature designed to ensure that developers do not make a mistake while using variables in different scopes.

That is why when you put a curly brace around the code, it works fine - because then the compiler knows you are explicitly scoping your code into different execution scopes.

Funny though that the following code:

class CTest
{
       public void Foo()
       {
             int x = 4;
             Console.WriteLine(x);
       }
 
        int x = -1;
}

compiles without an issue!  I'm probably misusing the scope of a class-level variable and the compiler doesn't even bother protecting it now!

Strange!