Why Can't a Duplicate Variable Name Be Declared in a Nested Local Scope

Why can't a duplicate variable name be declared in a nested local scope?

I don't think any of the answers so far have quite got the crucial line from the spec.

From section 8.5.1:

The scope of a local variable declared in a local-variable-declaration is the block in which the declaration occurs. It is an error to refer to a local variable in a textual position that precedes the local-variable-declarator of the local variable. Within the scope of a local variable, it is a compile-time error to declare another local variable or constant with the same name.

(Emphasis mine.)

In other words, the scope for the "later" variable includes the part of the block before the declaration - i.e. it includes the "inner" block containing the "earlier" variable.

You can't refer to the later variable in a place earlier than its declaration - but it's still in scope.

Why does using the same count variable name in nested FOR loops work?

You are actually making a new variable with the same name as another variable. Since they are in different scopes this is allowed, and the variable in the inner scope "owns" the name. You will not be able to access the outer-scoped i inside the inner scope.

The for loop declaration itself is part of the scope of the for loop, so counts as part of the inner-scope in the case of the second i.

Why can you have a duplicate variable name in java for a variable outside of a method?

Is this not a variable that is declared twice??

No, it is not. Because they both are in different scope. x outside of main function has class level scope while x inside of main has method/function level scope.

It is legal for 2 variables in different scope to have same name.

Please DO read §6.3. Scope of a Declaration from JLS. Below are few of the statement from that section.

The scope of a declaration is the region of the program within which
the entity declared by the declaration can be referred to using a
simple name, provided it is visible (§6.4.1).

A declaration is said to be in scope at a particular point in a
program if and only if the declaration's scope includes that point.

The scope of a local variable declaration in a block (§14.4) is the
rest of the block in which the declaration appears, starting with its
own initializer and including any further declarators to the right in
the local variable declaration statement.

There are lot of concepts related to scope like shadowing, so do read §6.4. Shadowing and Obscuring.

JLS is the best place to learn what is allowed and what is not allowed in Java. Feel free to read sections there.

Why doesn't C# allow me to use the same variable name in different scopes?

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/

Using a variable name used in a child scope

It is a design choice made by the designers of C#. It reduces potential ambiguity.

You can use it in one of the two places, inside the if or outside, but you can only define it in one place. Otherwise, you get a compiler error, as you found.

Scope of iteratee too wide

In fact, as surprising it might feel, the variable's scope is wider than what you'd expect. Give this code a try.

String aggregate = String.Empty;
foreach (Thing thing in things)
aggregate += thing.Value;
foreach (Thing thing in things)
aggregate += thing.Value;

It'll compile just fine. However, if you declare the thing outside as you did, the declaration span is outwards. It gets me too, sometime. :)



Related Topics



Leave a reply



Submit