Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Why doesn't this code compile in C#?

Discussion in 'Scripting' started by ArachnidAnimal, Dec 29, 2015.

  1. ArachnidAnimal

    ArachnidAnimal

    Joined:
    Mar 3, 2015
    Posts:
    1,727
    Code (csharp):
    1.  
    2. private void test() {
    3.  
    4.     if (true) {
    5.        bool b;
    6.     }
    7.  
    8.      bool b;
    9.  }
    10.  
    The error is: A local variable named `b' cannot be declared in this scope because it would give a different meaning to `b', which is already used in a `child' scope to denote something else.

    The error makes no sense. Both "bool b" are in completely different scopes.

    I would expect an error with this though:
    Code (csharp):
    1.  
    2. private void test() {
    3.  
    4.       bool b;
    5.  
    6.       if (true) {
    7.          bool b;
    8.      }    
    9.  
    10. }
    11.  
     
  2. apsdsm

    apsdsm

    Joined:
    Sep 26, 2013
    Posts:
    56
    Patico and ArachnidAnimal like this.
  3. Patico

    Patico

    Joined:
    May 21, 2013
    Posts:
    886
    @TTTTTa hmm, looks really strange. Perhaps, if-scope doesn't works like a scope here.
     
    ArachnidAnimal likes this.
  4. ForceVFX

    ForceVFX

    Joined:
    Jan 21, 2011
    Posts:
    612
    There is nothing to compile, you never call the routine,
    the first statement will always return true, which will always declare a local bool b, (never setting b's default value ie..true or false)..Then Re-declare b as boolean again, outside the scope of your first condition ( if yes = yes)..simple. .

    Your being non-sensical:

    "If true equals true declare B, declare B"
    Either way....same thing..same result.

    P
     
    Last edited: Dec 29, 2015
  5. ArachnidAnimal

    ArachnidAnimal

    Joined:
    Mar 3, 2015
    Posts:
    1,727
    This is just a watered-down example to show the compiler error.
     
    Last edited: Dec 29, 2015
  6. ArachnidAnimal

    ArachnidAnimal

    Joined:
    Mar 3, 2015
    Posts:
    1,727
    Thanks for the link.
    Apparently someone in the link explains:
    "Note that the scope of a variable is the lexical block it's part of - not just from the point of declaration onwards, but the whole scope."

    So the issue is the location of the second "bool b" within the function is irrelevant to the C# compiler, as far as scope is concerned. It's in the entire scope of the function, not just AFTER the if statement.

    If i recall from some other programming languages (like C), i don't think the compiler would have considered it an error though.
     
  7. zrrz

    zrrz

    Joined:
    Nov 14, 2012
    Posts:
    40
    Yes it should throw an error.
    On line 4 your compiler creates a variable called b and puts in on the stack.
    On line 7 you then try to add another variable called b onto the stack.
    There is already a variable on the stack called b. It was put there on line 4.

    C# doesn't actually compile in a line-by-line basis. Don't quote me on this, but I believe it compiles scope by scope. But the logic is the same. Your compiler doesn't let you put two variables named the same thing on the stack, because otherwise it wouldn't know which is which.
     
    Kiwasi and ArachnidAnimal like this.
  8. Patico

    Patico

    Joined:
    May 21, 2013
    Posts:
    886
    Good point, now I'm wondering what line thrown the error 5 or 8? Firstly I thougth it was 8, but if compiler working by scope, then error should be thrown at 5.
    Code (csharp):
    1.  
    2. private void test() {
    3.  
    4.     if (true) {
    5.        bool b;
    6.     }
    7.  
    8.      bool b;
    9.  }
    10.  
     
    ArachnidAnimal likes this.
  9. Munchy2007

    Munchy2007

    Joined:
    Jun 16, 2013
    Posts:
    1,732
    and yet this does compile...
    Code (CSharp):
    1.  
    2. private void Test()
    3. {
    4.    if(true)
    5.    {
    6.       bool b;
    7.    }
    8.  
    9.    if(true)
    10.    {
    11.       bool b;
    12.    }
    13. }
     
    ArachnidAnimal likes this.
  10. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    As it should. Both of those are scoped to the conditional containing them. You don't use a different letter of the alphabet in every for loop you create right? Same concept.

    Where it gets weird is alias variables in foreach loops - especially in closures. The way the current .NET compiler handles this is actually different than Unity's Mono compiler.
     
    ArachnidAnimal likes this.
  11. ArachnidAnimal

    ArachnidAnimal

    Joined:
    Mar 3, 2015
    Posts:
    1,727
    In MonoDevelop, it flags the second "bool b" on line 8 with error. Which is confusing, because the "bool b" inside the if statement should be the one flagged with the error. But, if you move the bool b to before the if statement, then it flags the second bool b as an error. (You can see by red squiggly line). I remember now I had this issue with a for loop a while ago and it confused me for hours.I would think the bool b inside the if statement should be the only one flagged with the error.

    bool.png

    The only explanation is it seems any declarations inside an if,while,for statement are moved before the if statement. So this:

    Code (csharp):
    1.  
    2. {
    3. if (true){
    4.     bool b; //1
    5. }
    6. bool b; //2
    7. }
    8.  
    is "converted" to:
    Code (csharp):
    1.  
    2. {
    3.   bool b; //1
    4. if (true){
    5. }
    6. bool b; //2
    7. }
    8.  
    If you think about it in this perspective, then the errors make sense.

    j
     
    Last edited: Dec 29, 2015
    zrrz likes this.
  12. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,744
    We human coders tend to think of variables as being brought into existence when we type 'bool b;' However, my understanding is that the instant code enters the scope where the variable is declared, it 'declares' them all. So it's 'marking out' the space for b (and reserving that name) on line 3, not line 7 where you wrote it.
     
    KelsoMRK and ArachnidAnimal like this.
  13. ArachnidAnimal

    ArachnidAnimal

    Joined:
    Mar 3, 2015
    Posts:
    1,727
    This is actually quite interesting to play around with.


    Here is a very interesting example:

    This code complies:
    Code (csharp):
    1.  
    2. class C
    3.    {
    4.      bool b;
    5.  
    6.      void M()
    7.      {    
    8.          //b = false; //Commented out
    9.        
    10.        bool b;
    11.  
    12.      }
    13.    }
    14.  
    whereas this code DOES NOT compile:

    Code (csharp):
    1.  
    2.   class C
    3.    {
    4.      bool b;
    5.  
    6.      void M()
    7.      {    
    8.  
    9.          b = false;
    10.        
    11.          bool b;
    12.  
    13.      }
    14.    }
    15.  
    The only difference is that b is assigned to. That is what is causing the compiler error in this example.

    After some digging, I found the explanation in the C# Language specification link:
    https://msdn.microsoft.com/en-us/library/ms228593.aspx

    7.6.2.1 Invariant meaning in blocks

    For each occurrence of a given identifier as a full simple-name (without a type argument list) in an expression or declarator, within the local variable declaration space (§3.3) immediately enclosing that occurrence, every other occurrence of the same identifier as a full simple-name in an expression or declarator 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.

    Apparently the inventors of C# do this to help programmers avoid bugs in the code.
    It's not that it can't compile, because this would work in other languages like C and C++.
    But in C#, a compiler error is reported
     
    Last edited: Dec 29, 2015
  14. DoubleLee

    DoubleLee

    Joined:
    Apr 11, 2014
    Posts:
    34
    You need to understand that variables local to a methods scope are pushed on the stack when the method is called not when the variable is in the code unless its in a different scope. So think of it as compiling to this...

    Code (CSharp):
    1.  
    2. void SomeMethod()
    3.     {
    4.     bool myVariable;
    5.     if (someCondition)
    6.         {
    7.         bool myVariable;
    8.         }
    9.     }
    10.  
    If you want to know more about this behavior google c# stack frames.
     
  15. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Honestly, the best answer is to learn to use different letters of the alphabet. This code Will compile no matter how you move the scope around.

    Code (CSharp):
    1. bool a;
    2. bool b;
    Using two variables with the same name so close to one another is just asking for trouble. ;)