8

Why am I not allowed to use a variable I declared inside do and use it inside the while part of a do/while loop?

do
{
   index += index;
   int composite = index + 1;
   // more code here
} while (UnsetBitmask(bitmasks, composite)); // cannot resolve symbol composite

First time I saw this I thought it was a compiler bug. So I restarted Visual Studio multiple times but still it does not recognize the variable in while.

What is wrong with the code, or is this a compiler bug?

Abel
  • 56,041
  • 24
  • 146
  • 247
M.kazem Akhgary
  • 18,645
  • 8
  • 57
  • 118
  • 3
    Look up variable scoping. `composite` only exists within the scope of your do while loop, and not outside of it. – Brandon Sep 01 '15 at 14:33
  • i konw this,but why compiler cant do this? – M.kazem Akhgary Sep 01 '15 at 14:33
  • 7
    Why *should* an out-of-scope variable be usable outside its scope? It would be a bug if you could do this – Panagiotis Kanavos Sep 01 '15 at 14:33
  • 1
    @M.kazemAkhgary `composite` **only** exists within (read: within `{ }` ) the while loop. You're trying to use it outside the loop, which you can't do. – sab669 Sep 01 '15 at 14:34
  • @PanagiotisKanavos it would be nice if the compiler change that behavior and limit scope until after `while();`.also compiler already changes behavior of while if you put `do{}` before while. – M.kazem Akhgary Sep 01 '15 at 14:39
  • 2
    @M.kazemAkhgary that would break a lot of other scoping rules. Things defined within `{ }` don't exist outside them, the compiler should not make "special cases", usually loops are unrolled or converted into other forms anyway which makes it even more difficult. – Ron Beyer Sep 01 '15 at 14:42
  • 1
    @M.kazemAkhgary no it wouldn't. This behavior wouldn't be logical. It's a clear bug to try to use a variable *outside* its scope. In fact, such arbitrary behaviour was one of the main pain points of classic Visual Basic – Panagiotis Kanavos Sep 01 '15 at 14:43

9 Answers9

16

Your variable is used outside the do/while (in C# the curlies typically define the scope) and since it is declared inside the do-while, you cannot use it outside that scope.

You can fix this by simply declaring it outside the loop.

int composite = 0;   // you are not required to set it to zero, as long 
                     // as you do not use it before you initialize it
do
{
   index += index;
   composite = index + 1;
   // more code here
} while (UnsetBitmask(bitmasks, composite)); 

Note (1), it is common practice to declare and set a variable in one go, but this is not a requirement, as long as you set it before you use it.

Note (2): in C#, curly braces {....} define the scope of variables. You cannot use a variable outside its scope, it is not "visible" anymore, in fact, once it goes out of scope, it is ready to be garbage collected and its contents can be undefined.


i konw this,but why compiler cant do this

You asked this in the comments. The answer is less trivial than it may seem. It highly depends on the language definition. Some languages, like Perl, or older BASIC, allow variables to be declared at any level and in any scope. Other languages allow scoping of variables and require variables to be declared prior to their use (C#, Java, C++, Python). Usually, but not necessarily, this is common for statically typed languages, as the compiler needs to know beforehand what type of data you want to put in the variable, in order to do type checking.

If a compiler would force declaration, but not scope, it means that all variables would be global, which is hard in larger programs, as as a programmer, you will have to maintain where you used what variable names and maintain uniqueness. This is very tedious (think COBOL).

C# added the dynamic keyword, which allows for variables that have dynamic type, but this still requires you to define the variable prior to its use.

A compiler can do this, but the designers of C# have decided that clear language is better, and in their opinion, declared variables are a good thing, because it prevents spurious errors and impossible-to-follow code:

// can you see the problem?
va1l = 1;
val1 = 2;
vall = va1l + vall;

Forcing you to declare variables and to have them scoped prevents this and related kinds of errors.

Community
  • 1
  • 1
Abel
  • 56,041
  • 24
  • 146
  • 247
  • I think you mean it's "inside" the do/while. – juharr Sep 01 '15 at 14:34
  • @juharr, thankx, but no, I meant it is is _used_ outside its scope. I'll edit. – Abel Sep 01 '15 at 14:35
  • In this case you don't need to initialize the variable `composite` to zero before the loop. – Luca Cremonesi Sep 03 '15 at 19:02
  • @LucaCremonesi: that is correct. But since the OP wrote _"more code here"_, I wasn't sure that potentially, more code came before the shown code. Bottom line, I wanted to prevent his total code block to fail with a "use of uninitialized variable" error. But I agree, as written it is not needed to initialize it. I have added a comment to that extent. – Abel Sep 04 '15 at 08:28
7

This is not a bug. The condition inside the while loop is outside of the block in which the variable is defined.

int composite;
do
{
   index += index;
   composite = index + 1;
   // more code here
} while (UnsetBitmask(bitmasks, composite));
Sam
  • 3,070
  • 3
  • 20
  • 26
2

the scope of this variable is just inside the loop .... You cannot use it outside the loop

You should do something like this ....

int composite;
do
{
   index += index;
   composite = index + 1;
   // more code here
} while (UnsetBitmask(bitmasks, composite)); 
2

While { ... } means a codeblock all variables within that block are limited to that special scope. Your condition is outside this scope so it cannot access the variable there. Declare it outside the loop and it works:

int composite = 0;
do
{
    index += index;
    composite += index + 1;
    // more code here
} while (UnsetBitmask(bitmasks, composite));
MakePeaceGreatAgain
  • 35,491
  • 6
  • 60
  • 111
2

Per Specification the condition variable for do .. while should be declared outside the loop else in every iteration the variable will get re-initialized which doesn't make sense.

        int composite;
        do
        {
            index += index;
            composite = index + 1;
            // more code here
        } while (UnsetBitmask(bitmasks, composite)); 
Rahul
  • 76,197
  • 13
  • 71
  • 125
2

More general rule: you can't use variable outside its scope that's in C# it's {...}, e.g.

  {
   int x = 123;
   ...
  }
  x = 456; // <- compile time error

do {} while in your code just means that the scope belongs to the loop.

Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
2

I understand that the "while" is outside the block, but consider this:

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

Here, the variable "i" is block scoped (not visible outside the for's block), in fact a new "instance" is created on each loop iteration. But the actual definition is outside the block.

You could say the "for" declaration belongs to the block, but then I would say the "while" also belongs to the block. It's just not consistent!

  • (1) It is not a new "instance" (even with quotation marks), because the variable keeps its value between iterations. (2) There is no inconsistency, because you never declare variables in `while` condition. (3) This does not answer the question, so you should've created a comment, not post an answer. – C-F Dec 04 '22 at 21:30
0
    int composite;
do
{
   index += index;
   composite = index + 1;
   // more code here
} while (UnsetBitmask(bitmasks, composite));
  • according to the format of do ehile declaration of variable must be done before starting the loop – codemaster Sep 01 '15 at 17:43
  • 1
    you can edit your answer to add (or correct) information, rather than adding a comment. Editing your answer is preferable because it makes it easier for others to find and read the information later. – dsh Sep 01 '15 at 18:01
0

If you really do not want to move the variable declaration outside the loop body (as all the answers suggest), there is another (pretty obvious and pretty ugly) workaround:

do
{
   index += index;
   int composite = index + 1;
   // more code here

   // check the condition inside the loop body, where the variable exisits
   if(!UnsetBitmask(bitmasks, composite)) break;
} while (true);
C-F
  • 1,597
  • 16
  • 25