6

The code below produces this error in Visual Studio 2012; "A local variable named 'x' cannot be declared in this scope because it would give a different meaning to 'x', which is already used in a 'child' scope to denote something else"

for (int x = 0; x < 9; x++) 
  {
     //something
  }
int x = 0;

However. When modified as below I get this error; "The name 'x' does not exist in the current context"

for (int x = 0; x < 9; x++) 
  {
     //something
  }
x = 0;

Is this a huge contradiction or am I missing something?

Soner Gönül
  • 97,193
  • 102
  • 206
  • 364
  • There was an Eric Lippert post about this... – usr Jan 08 '14 at 19:53
  • 1
    @usr It was a series. [Part 1](http://blogs.msdn.com/b/ericlippert/archive/2009/11/02/simple-names-are-not-so-simple.aspx), [Part 2](http://blogs.msdn.com/b/ericlippert/archive/2009/11/05/simple-names-are-not-so-simple-part-two.aspx). To answer the OP's question, no, it is not a contridiction. To quote Eric's linked article, the key lies in, "it will be vital to understand the difference between scope and declaration space." – Servy Jan 08 '14 at 19:54
  • as per my understanding the first declaration will give error in any version of VS. because in .NET (OOPS) when it comes to declaration Scope does matter not the order / sequence. – Venkatesh Ellur Jan 08 '14 at 19:58

7 Answers7

11

So far no one except Rik has put their finger on the correct answer.

Read the error messages again, very carefully. They are clearly explaining the errors. The first error is:

A local variable named 'x' cannot be declared in this scope because it would give a different meaning to 'x', which is already used in a 'child' scope to denote something else

Actually read the error message. It says it is illegal to use the same name to mean two different things. The error has nothing to do with the scope of the outer x per se; it has to do with the fact that x is used to mean two things in the same outer scope.

As Rik points out, the purpose of this rule is to avoid situations where the developer becomes confused about the meaning of x. A given name almost always means the same thing throughout a block. (There are some subtle exceptions but let's not go into those today.) This rule also helps prevent bugs introduced by re-ordering statements within a method and thereby subtly changing the meaning of the names. If the meaning of a name is invariant within a block then code edits within that block can be made with confidence.

A number of the answers say that scopes are not allowed to overlap. Yes they are. Local variable scopes are not allowed to overlap, but scopes are allowed to overlap. For example:

class C
{
    int x;
    void M()
    {
        int y = this.x;
        for(int x = 0; x < 10; ++x) {}
    }
}

Perfectly legal even though there are two things called x in scope at the same time. But this is not legal:

class C
{
    int x;
    void M()
    {
        int y = x; // Means this.x
        for(int x = 0; x < 10; ++x) {} // means local x
    }
}

Now the simple name x means two different things inside the body of M, and that is what is illegal. Again, make sure you understand this: using the same name to mean two things in the same scope is what is illegal. It is not illegal to overlap scopes.

Now your second error:

"The name 'x' does not exist in the current context"

The name x is only valid inside the for statement. A for statement:

for (declarations ; condition ; increment ) body

is logically equivalent (modulo break and continue behaviour)to

{
    declarations;
    while(condition)
    {
        body
        increment
    } 
}

Note the outer braces. Anything in that declaration can be used throughout the condition, body or increment, but is not in scope outside.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • Holy god.. I never thought this situation could be this much specific. And you explained it as much as simple. Thanks Eric! – Soner Gönül Jan 09 '14 at 07:27
6

The first is an error because it is equivalent to this:

int x;
for (int x = 0; x < 9; x++) 
{
   //something
   // 'x' is ambiguous here
}
x = 0;

The way variable declarations work in C#, that is the same as your first sample.

The second is an error because the 'x' variable defined in the loop is only valid in the loop.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
  • So you are saying that it dose not matter where the declaration is happen, it is always placed on the top of the method, right? – Armen Jan 08 '14 at 19:57
  • Sort of. You can't use a variable before you declare it, but the name you declare is reserved as if it were declared at the top of the scope. – Joel Coehoorn Jan 08 '14 at 19:58
  • 4
    The rule that is being violated here has nothing to do with where the outer x is in scope! Consider for example `class C { int x; void M() { int y = x; for(int x = 0; ; ) {} }`. That's also illegal and for the same reason. But it has nothing to do with the scope of the outer `x`! Consider `class C { int x; void M() { int y = this.x; for(int x = 0; ; ) {} }` That is perfectly legal even though the outer `x` is in scope throughout! The violation here is that the *simple name* `x` must not be used to mean two different things in the same scope, not that the scopes overlap. Scopes can overlap. – Eric Lippert Jan 08 '14 at 21:27
  • That's what I was trying to get at here, especially when you look at my prior comment: "the **name** you declare is reserved". It's whey I bothered to write the comment at all: to reply to the question about declaration location not mattering. It does matter; the scope does change, because the variable is not in scope until it's declaration. But the issue in the original question is not about the variable scope: it's about the naming conflict, and the ambiguity it creates. – Joel Coehoorn Jan 08 '14 at 22:49
5

C# is stopping you from creating a confusing situation in which it is easy to make mistakes about what x actually refers to.

Rik
  • 28,507
  • 14
  • 48
  • 67
0

It's not a contradiction. the int x you define in the for is scoped to the for loop, meaning:

for (int x = 0; x < 9; x++) 
{
    //x is only alive here.
}

//you can't use it here.

however you can't create yet another x variable in a parent scope (that is, the method scope):

public void MyMethod()
{
   int x = 0; //method-scoped variable.

    for (int x = 0; x < 9; x++)  //for-scoped variable, with the same name, invalid.
    {
        //here you have 2 "x", which one to use? invalid.
    }

   //the first x is available here
}
Federico Berasategui
  • 43,562
  • 11
  • 100
  • 154
0

A series of statements surrounded by curly braces form a block of code. A method body is one example of a code block. Code blocks often follow a control statement. Variables or constants declared within a code block are only available to statements within the same code block.

Check this link: http://msdn.microsoft.com/en-us/library/ms173143%28v=vs.80%29.aspx

Doing this:

for (int x = 0; x < 9; x++) 
  {
     //something
  }
x = 0;

Is detected by the semantic analyzer as an error, because x is no longer available outside the for loop.

Although when you do an int x inside of an inner block and declare a int x outside of the inner block, the compiler warns you only about a possible error in your semantics.

for (int x = 0; x < 9; x++) 
  {
     //something
  }

//theoretically allowed, but the C# compiler identifies it as an error.
int x = 0; //caution x declare before

If you are intrigued by this, the explanation is quite simple:

As stated in the section 3.7 of the language spec. “The scope of a local variable declared in a local-variable-declaration (8.5.1) is the block in the which the declaration occurs”.

The scope of x is therefore the entire function where you declared it, and that means that the declaration/use outside the for loop is a re=use, and therefore is not allowed.

This behavior is intended to make incorrect re-use of variable names (such as in a cut and paste) less likely.

Regards.

João Pinho
  • 3,725
  • 1
  • 19
  • 29
  • 1
    The second example does not result in a compiler warning, it results in a compiler *error*. That's actually a significant difference. – Servy Jan 08 '14 at 20:03
  • To be very precise, `int x = 0;` is outside the curly braces in your first example, so counting curly braces is not the key. – Thomas Weller Jan 08 '14 at 20:03
0

It's due to child scope.

Following will not work as both i's are in same scope

for (int i = 0; i < 100; i++)
{
    Console.WriteLine(i);
}

int i = 10;
Console.WriteLine(i);

Following will also not work as both i's are still in same scope

{
    for (int i = 0; i < 100; i++)
    {
        Console.WriteLine(i);
    }
}
int i = 10;
Console.WriteLine(i);

Following will work just fine

{
    for (int i = 0; i < 100; i++)
    {
        Console.WriteLine(i);
    }
}
{
    int i = 10;
    Console.WriteLine(i);
}
Mayank
  • 8,777
  • 4
  • 35
  • 60
  • This lacks an explanation as to *why*. – Servy Jan 08 '14 at 20:03
  • *You also need to know that a for-loop is treated as though there are "invisible braces" around the whole thing.* from http://stackoverflow.com/questions/1196941/confused-with-the-scope-in-c-sharp – Mayank Jan 08 '14 at 20:05
  • It *is* due to child scope but you are not explaining the actual error that is being produced. See my comment to Joel's answer. – Eric Lippert Jan 08 '14 at 21:28
-1

Variable x is our of scope because it was declared in the loop. If you anyway want to use the same variable again, try this - (Not recommended though - standards wise)

int x = 0;
for (x = 0; x < 9; x++){
//something
}
x = 0;
Suyash Khandwe
  • 386
  • 3
  • 11