I have two code samples. The first does not compile, but the second does.
Code Sample 1 (does not compile)
public void MyMethod(){
int i=10;
for(int x=10; x<10; x++) {
int i=10; // Point1: compiler reports error
var objX = new MyOtherClass();
}
var objX = new OtherClassOfMine(); // Point2: compiler reports error
}
I understand why the compiler reports an error at Point1
. But I don't understand why it reports an error at Point2
. And if you say it is because of the organization inside MSIL, then why does the second code example compile?
Code sample 2 (compiles)
public void MyMethod(){
for(int x=10; x<10; x++) {
int i=10;
var objX = new MyOtherClass();
}
for(int x=10; x<10; x++) {
int i=10;
var objX = new MyOtherClass();
}
}
If the simple rules of variable scope apply in Code Sample 2, then why don't those same rules apply to Code Sample 1?
You are allowed to use the same variable name in non-overlapping scopes. If one scope overlaps another, though, you cannot have the same variable declared in both. The reason for that is to prevent you from accidentally using an already-used variable name in an inner scope, like you did with
i
in the first example. It's not really to prevent theobjX
error since that would, admittedly, not be very confusing, but the error's a consequence of how the rule is applied. The compiler treatsobjX
as having provenance throughout the scope in which it is declared both before and after its declaration, not just after.In the second example the two
for
loops have independent, non-overlapping scopes, so you are free to re-usei
andobjX
in the second loop. It's also the reason you can re-usex
as your loop counter. Obviously, it would be a dumb restriction if you had to make up different names for eachfor(i=1;i<10;++i)
style loop in a function.On a personal note, I find this error annoying and prefer the C/C++ way of allowing you do to whatever you want, confusion be damned.
you should not be getting a compilation error with the second sample. Try renaming the variables to different letters/names and recompile again as it may be so other issue with the code most likely you've missed a curly bracket and changed the variables scope range.
There are two relevant rules here.
The first relevant rule is:
(And another answer on this page calls out another location in the specification where we call this out again.)
That alone is enough to make this illegal, but in fact a second rule makes this illegal.
The second relevant rule in C# is:
You also need to know that a for-loop is treated as though there are "invisible braces" around the whole thing.
Now that we know that, let's annotate your code:
You have three "simple names", i, x and objX. You have five variables, which I've labeled i1, x2, i3, objX3, and objX1.
The outermost block that contains usages of i and objX is block 1. Therefore, within block 1, i and objX must always refer to the same thing. But they do not. Sometimes i refers to i1 and sometimes it refers to i3. Same with objX.
x, however, only ever means x2, in every block.
Also, both "i" variables are in the same local variable declaration space, as are both "objX" variables.
Therefore, this program is an error in several ways.
In your second program:
Now you have three simple names again, and six variables.
The outermost blocks that first contain a usage of simple name x are blocks 2 and 4. Throughout block 2, x refers to x2. Throughout block 4, x refers to x4. Therefore, this is legal. Same with i and objX -- they are used in blocks 3 and 5 and mean different things in each. But nowhere is the same simple name used to mean two different things throughout the same block.
Now, you might note that considering all of block 1, x is used to mean both x2 and x4. But there's no mention of x that is inside block 1 but NOT also inside another block. Therefore we don't count the inconsistent usage in block 1 as relevant.
Also, none of the declaration spaces overlap in illegal ways.
Therefore, this is legal.
From the C# Language Specification...
In code sample 1, both i and objX are declared in the scope of the function, so no other variable in any block inside that function can share a name with them. In code sample 2, both objXs are declared inside of the for loops, meaning that they do not violate the rule of not redeclaring local variables in inner scopes from another declaration.