Variable scope confusion in C#

Related searches

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?

There are two relevant rules here.

The first relevant rule is:

It is an error for a local variable declaration space and a nested local variable declaration space to contain elements with the same name.

(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:

For each occurrence of a given identifier as a simple-name in an expression or declarator, within the local variable declaration space, immediately enclosing block, or switch-block of that occurrence, every other occurrence of the same identifier as a simple-name in an expression or declarator within the immediately enclosing block or switch-block must refer to the same entity. This rule ensures that the meaning of a name is always the same within a given block, switch block, for-, foreach- or using-statement, or anonymous function.

(UPDATE: This answer was written in 2009; in recent versions of C# this rule has been eliminated because it was considered to be too confusing; the user confusion produced was not worth the small number of bugs that were prevented. See this answer for details.)

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:

public void MyMethod()
{ // 1
    int i=10; // i1
    { // 2 -- invisible brace
      for(int x=10; x<10; x++) // x2
      { // 3
        int i=10;  // i3
        var objX = new MyOtherClass(); // objX3
      } // 3
    } // 2
    var objX = new OtherClasOfMine(); // objX1
} // 1

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:

public void MyMethod()
{ // 1
    { // 2 -- invisible 
      for(int x=10; x<10; x++)   // x2
      { // 3
        int i=10;  // i3
        var objX = new MyOtherClass(); // objX3
      } //3 
    } // 2
    { // 4 -- invisible
      for(int x=10; x<10; x++)  // x4
      { // 5
        int i=10;  // i5
        var objX = new MyOtherClass();  // objX5
      } //5
   } // 4
} // 1

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.

Variable Scope Confusion C#, The scope controls the lifetime and visibility of the variable. It is good programming practice to use the most restrictive scope possible for your variables. You can� When a variable is declared in a method of a C# program, its scope is pre-defined and its visibility is defined for the rest of the program. When it's created this way, the variable will be available as long as its method is in execution. However, when the control is passed to another method, its scope ends.

From the C# Language Specification...

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.

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.

C# Syntax - Scope and Lifetime, chance of confusion there. For reference, the rules are in �3.7 Scopes of the C# spec: The scope of a local variable declared in a local-variable-declaration is � In C/C++, all identifiers are lexically (or statically) scoped, i.e.scope of a variable can be determined at compile time and independent of the function call stack. But the C# programs are organized in the form of classes. So C# scope rules of variables can be divided into three categories as follows: Class Level Scope; Method Level Scope

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 the objX error since that would, admittedly, not be very confusing, but the error's a consequence of how the rule is applied. The compiler treats objX 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-use i and objX in the second loop. It's also the reason you can re-use x as your loop counter. Obviously, it would be a dumb restriction if you had to make up different names for each for(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.

Why doesn't C# have local scope in case blocks?, Reduce the scope of the variable so that it is only visible in the scope where it is scope, something most seasoned programmers can testify is very confusing� The scope of a variable determines its visibility to the rest of a program. In the examples throughout the C# Fundamentals tutorial, variables have been defined within methods . When created in this way, the scope of the variable is the entire method after the declaration.

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.

Reduce Scope of Variable, In any language, i would ask for the names of these variables to be different to make it clear, and to remove any chance of confusion about what� The scope of a variable is simply the region of the program in which that variable is usable. Scope applies to methods as well as variables. The scope of an identifier (of a variable or method) is linked to the location of the declaration that introduces the identifier into the program. Local Scope … Scope of the Variable in C# Read More »

C# is too restrictive about local variable scopes � Issue #2574, The scope of a variable is a region of code that indicates where the variables are being accessed. For a variable, it has the following levels − Method Level. Variable declared inside a method is a local variable. Class Level. Variable declared inside a class is a local variable are class member variables. Let us see an example of scope of

Quick video explaining what the scope of a variable is. Quick video explaining what the scope of a variable is. C# Global Variable Tutorial - Duration: 13:06. SuncoastSoftware 21,678 views.

Variables. The default scope for variables of any type that are created with the cfset and cfparam tags. A Variables scope variable is available only on the page on which it is created and any included pages (see also the Caller scope).Variables scope variables created in a CFC are available only to the component and its functions, and not to the page that instantiates the component or calls

Comments
  • Thanks that was very descriptive.
  • It is easy to remember it as a rule ...but some how i m not able digest why that is limited , wrt first code and objX: i created a variable in a block and when i come out of a loop it shud be finished, just like i cant access it outside the block.
  • Look at it this way. It should always be legal to move the declaration of a variable UP in the source code so long as you keep it in the same block, right? If we did it the way you suggest, then that would sometimes be legal and sometimes be illegal! But the thing we really want to avoid is what happens in C++ -- in C++, sometimes moving a variable declaration up actually changes the bindings of other simple names!
  • You should read Eric Lippert's post "C++ and the Pit Of Despair". It will help explain why the C# design team made the decisions they did. I particularly like this quote: "when I ask you guys what the 'intuitively obvious' thing to do is, significant fractions of the population disagree!"
  • He clearly states the second sample compiles, but the first sample does not. I assume this is why you got a downvote for this.