Reputation: 330892
Like for instance:
if ( this.IsValid )
{
Matrix matrix = new Matrix();
}
Matrix matrix = new Matrix();
The compiler warns me saying:
"A local variable named 'matrix
' cannot be declared in this scope because it would give a different meaning to 'matrix
', which is already used in a 'child' scope to denote something else.
Aren't these variables in different scopes, so I wouldn't be able to access the first matrix
from outside the if statement anyway?
Upvotes: 20
Views: 9954
Reputation: 659984
UPDATE: The answer below from 2011 is correct for earlier versions of C#; in more recent versions, the rule described the answer has been removed from C#. The design team determined that the rule caused more confusion amongst developers leading to questions like this one than the buggy programs prevented would warrant, even after I greatly improved the error messages to more clearly diagnose the problem.
The answers given so far are very confusing. The correct analysis of the problem starts by reading the error message. The error message is telling you what is actually wrong:
"A local variable named 'matrix' cannot be declared in this scope because it would give a different meaning to 'matrix', which is already used in a 'child' scope to denote something else.
Read that carefully. It is telling you precisely which rule of C# is being violated, namely that you are not allowed to use the same name to refer to two different things in the same scope. (Actually, the error message is slightly wrong; it should say "local variable declaration space" where it says "scope", but that is pretty wordy.)
This rule is documented in the C# 4.0 specification, section 7.6.2.1: Simple names, Invariant meaning in blocks.
(It is also illegal to have two local variables of the same name in overlapping declaration spaces. The compiler could be reporting that error as well, but it reports the more general error in this case.)
Aren't these variables in different scopes, so I wouldn't be able to access the first matrix from outside the if statement anyway?
Yes. That statement is true but irrelevant. The error here is that the same simple name has been used to refer to two different things in the same local variable declaration space.
Consider this scenario:
class C
{
int x;
void M()
{
x = 10; // means "this.x"
for(whatever)
{
int x = whatever;
}
}
}
Same deal. The error here is that the simple name "x" was used in the outer declaration space to refer to this.x, and was used in the inner declaration space to mean "local variable". Using the same simple name to refer to two different things in the same declaration space -- remember, the inner declaration space is a part of the outer one -- is both confusing and dangerous, and is therefore illegal.
It is confusing for obvious reasons; one has a reasonable expectation that a name will mean the same thing everywhere throughout the declaration space in which it is first used. It is dangerous because small code edits are prone to changing the meaning:
class C
{
int x;
void M()
{
int x;
x = 10; // no longer means "this.x"
for(whatever)
{
x = whatever;
}
}
}
If the declaration spaces in which the simple names are first used are not overlapping then it is legal for the simple names to refer to different things:
class C
{
int x;
void M()
{
{
x = 10; // means "this.x"
}
for(whatever)
{
int x = whatever; // Legal; now the
}
}
}
For more information, and an amusing story about fried food, see
http://blogs.msdn.com/b/ericlippert/archive/tags/simple+names/
Upvotes: 18
Reputation: 22433
You can always do this...
void YourMethod()
{
if ( this.IsValid )
{
Matrix matrix = new Matrix();
}
{
Matrix matrix = new Matrix();
}
}
...Each set of braces {}
allows you to nest another level of scope. The issue you are having is the fact that nested scopes include the scope of their parents. If you declare a siblng scope it will be able to resuse variables within the same parent. But as others have pointed out this may become confusing later.
Upvotes: 6
Reputation: 1215
Matrix matrix = new Matrix();
if ( this.IsValid )
{
Matrix matrix = new Matrix();
}
Imagine it instead written like that, it is a bit more obvious I would think why this is not allowed since the second instance should obviously be considered a clash. Not being able to access the outer variables within child scopes would be bad.
From MSDN "A: This is correct behavior, and is covered in section 3.7 of the language spec. It says, “The scope of a local variable declared in a local-variable-declaration (8.5.1) is the block in the which the declaration occurs”." ... "This behavior is inteded to make incorrect re-use of variable names (such as in a cut and paste) less likely." (http://blogs.msdn.com/b/csharpfaq/archive/2004/05/18/why-can-t-i-use-the-same-variable-as-an-inner-loop-does.aspx)
Upvotes: 1
Reputation: 8554
It is my belief that this is done in order to avoid obscure mistakes or code that's hard to read.
Using the same name of variable between a method scope and a child scope can lead to code that's very hard to read, since the variable type and, worse, meaning, can change and the only hint to the reader will be type declaration keyword before the variable.
However, I can also tell you that the IL generated for methods by the C# compiler will stick all variable declarations at the top, so maybe this decision driver was to simplify the variable parsing tree for the compiler.
In fact, you can find this at MSDN:
The scope of a name is the region of program text within which it is possible to refer to the entity declared by the name without qualification of the name. Scopes can be nested, and an inner scope may redeclare the meaning of a name from an outer scope. (This does not, however, remove the restriction imposed by Section 3.3 that within a nested block it is not possible to declare a local variable with the same name as a local variable in an enclosing block.) The name from the outer scope is then said to be hidden in the region of program text covered by the inner scope, and access to the outer name is only possible by qualifying the name.
Emphasis added.
And, from Section 3.3:
Each block or switch-block creates a different declaration space for local variables and constants. Names are introduced into this declaration space through local-variable-declarations and local-constant-declarations. If a block is the body of an instance constructor, method, or operator declaration, or a get or set accessor for an indexer declaration, the parameters declared in such a declaration are members of the block's local variable declaration space. The local variable declaration space of a block includes any nested blocks. Thus, within a nested block it is not possible to declare a local variable with the same name as a local variable in an enclosing block.
Emphasis added.
So, the thing is that while the scopes are different, the variable space is the same.
Upvotes: 7
Reputation: 32831
Imagine a human being trying to read this code.
From the point of view of another developer trying to read your code, can you see how confusing it would be to have two different variables with the same name? Even if they are representing the same thing, it's just too hard to deal with two things with the same name.
Upvotes: 2