views:

246

answers:

4

I get the following error in Visual Studio 2008:

Error 1 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

This is my code:

for (int i = 0; i < 3; i++)
{
  string str = "";
}

int i = 0; // scope error
string str = ""; // no scope error

I understand that str ceases to exist once the loop terminates, but I also thought that the scope of i was confined to the for loop as well.

So i has the same scope as a variable declared just outside of the for loop?

Edit:

Just to be clear, I am using C#. I am debating removing the "C" tag. However, since the correct answer explains the difference between the two, I figure it makes sense to leave both tags.

I had an error in my code comment above:

for (int i = 0; i < 3; i++)
{
  string str = "";
}

int i = 0; // scope error
string str = ""; // also scope error,
                 // because it's equivalent to declaring
                 // string str =""; before the for loop (see below)
+2  A: 

Yea. Syntactically: The new scope is inside the block defined by the curly strings. Functionally: There are cases in which you may want to check the final value of the loop variable (for example, if you break).

Nicolas78
+1 right, inside the {}, that totally makes sense and makes it consistent!
JohnB
+2  A: 

Just some background information: The sequence doesn't come into it. There's just the idea of scopes - the method scope and then the for loop's scope. As such 'once the loop terminates' isn't accurate.

You're posting therefore reads the same as this:

int i = 0; // scope error
string str = ""; // no scope error

for (int i = 0; i < 3; i++)
{
  string str = "";
}

I find that thinking about it like this makes the answers 'fit' in my mental model better..

Kieren Johnstone
+1 Thanks and great point! That clears things up even better! (but doesn't directly answer my question, so you don't get the check)
JohnB
The double declaration of `str` is fine in C++ but it's a scoping error in C#. The problem in the OP's question is not about having two variables declared in the *same* scope, it's that C# doesn't let you have the same variable in *nested* scopes because it could be confusing. C++ let's you do the confusing thing.
John Kugelman
John, sure, but what was it that you said that made my answer inappropriate or unhelpful (assuming you voted me down)? As I said, it's some background information, and as the OP said, 'Thanks and great point! That clears things up even better'.
Kieren Johnstone
The two `str` variables *do* cause an error in C#, just like the two `i` variables do. And neither one causes an error in C++. Your code snippet is wrong in either language. I don't mean to pile on, but I think your answer added to the OP's confusion rather than clearing it up.
John Kugelman
@John Kugelman: it was my fault for saying `string str = ""; // no scope error` initially. However, Kieren really nailed why I was getting my error first (which is because the sequence is reversible to the compiler). However, I'm giving the check to Jeff Dege because he provided a clearer answer.
JohnB
@John Kugelman: I think you should take away his -1
JohnB
@John Kugelman - No, I wasn't saying that was valid code. Read the question again. I said 'your posting therefore reads the same as this'. And the original posting has the error, so I was re-iterating the same code, but with the lines moved. I wasn't suggesting a solution. Please re-read answers before you decide to vote them down; you are wrong.
Kieren Johnstone
+2  A: 

The incrementor does not exist after the for loop.

for (int i = 0; i < 10; i++) { }
int b = i; // this complains i doesn't exist
int i = 0; // this complains i would change a child scope version because the for's {} is a child scope of current scope

The reason you can't redeclare i after the for loop is because in the IL it would actually declare it before the for loop, because declarations occur at the top of the scope.

Jimmy Hoffa
+1 Hoffa: I guess you already figured it out, but why did you delete your sample code? That was a great point.
JohnB
@JohnB: I was claiming the error incorrectly, fixed now. Sometimes just have to think through these things :)
Jimmy Hoffa
@JohnB: please explain what language you're using.
Luca Matteis
@Luca Matteis: C#, but I didn't think it mattered!
JohnB
Hoffa also pointed out the the sequence of variable declaration is reversible, which is a good point, but Jeff Dege has the real answer.
JohnB
+12  A: 

I think you're all confusing C++ and C#.

In C++, it used to be that the scope of a variable declared in a for expression was external to the block that followed it. This was changed, some time ago, so that the scope of a variable declared in a for expression was internal to the block that followed it. C# follows this later approach. But neither has anything to do with this.

What's going on here is that C# doesn't allow one scope to hide a variable with the same name in an outer scope.

So, in C++, this used to be illegal. Now it's legal.

for (int i; ; )
{
}
for (int i; ; )
{
}

And the same thing is legal in C#. There are three scopes, the outer in which 'i' is not defined, and two child scopes each of which declares its own 'i'.

But what you are doing is this:

int i;
for (int i; ; )
{
}

Here, there are two scopes. An outer which declares an 'i', and an inner which also declares an 'i'. This is legal in C++ - the outer 'i' is hidden - but it's illegal in C#, regardless of whether the inner scope is a for loop, a while loop, or whatever.

Try this:

int i;
while (true)
{
    int i;
}

It's the same problem. C# does not allow variables with the same name in nested scopes.

Jeff Dege
**This** is the correct answer. C# doesn't let you hide variables because it can be confusing. C++ doesn't care. It has nothing to do with `for` loop syntax, or whether variables are declared at the top or bottom of the function, or anything else...
John Kugelman
I've found that actually reading the error message is sometimes helpful.
Jeff Dege
Thank you guys!
JohnB