33

The following syntax is valid:

while (int i = get_data())
{
}

But the following is not:

do
{
} while (int i = get_data());

We can see why via the draft standard N4140 section 6.4:

1 [...]

condition:
     expression
     attribute-specifier-seqopt decl-specifier-seq declarator = initializer-clause
     attribute-specifier-seqopt decl-specifier-seq declarator braced-init-list

2 The rules for conditions apply both to selection-statements and to the for and while statements (6.5). [...]

and section 6.5

1 Iteration statements specify looping.

      iteration-statement: 
             while ( condition ) statement
             do statement while ( expression ) ;

Instead, you're forced to do something ugly like:

int i = get_data();
do
{
} while ((i = get_data())); // double parentheses sic

What is the rationale for this?

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
user4351360
  • 461
  • 4
  • 6
  • 5
    Reason you can't is because `while` condition lies outside of the the `do-while` scope. Now why you can't, most probable due to grammar limitations. – 101010 Dec 11 '14 at 19:27
  • Note, we can find links to the [draft standards here](http://stackoverflow.com/q/81656). – Shafik Yaghmour Dec 11 '14 at 21:09
  • Note you can always wrap more brackets around it: `{ int i; do {...}while(...); }`. – luser droog Dec 12 '14 at 05:53
  • I believe that C++, like C, is intended to be parseable by a single-pass parser, and here the compiler doesn't see the declaration until at the end of the while loop. – Thomas Padron-McCarthy Dec 12 '14 at 13:23
  • I've posted a follow-up question here http://stackoverflow.com/questions/27460527/scope-of-declarations-in-the-body-of-a-do-while-statement – sfjac Dec 13 '14 at 15:35

6 Answers6

39

It seems like scoping would be the issue, what would be the scope of i declared in the while portion of a do while statement? It would seem rather unnatural to have a variable available within the loop when the declaration is actually below the loop itself. You don't have this issue with the other loops since the declarations comes before the body of the loop.

If we look at the draft C++ standard section [stmt.while]p2 we see that for the while statement that:

while (T t = x) statement

is equivalent to:

label:
{ // start of condition scope
    T t = x;
    if (t) {
        statement
    goto label;
    }
} // end of condition scope

and:

The variable created in a condition is destroyed and created with each iteration of the loop.

How would we formulate this for the do while case?

and as cdhowie points out if we look at section [stmt.do]p2 it says (emphasis mine):

In the do statement the substatement is executed repeatedly until the value of the expression becomes false. The test takes place after each execution of the statement.

which means the body of the loop is evaluated before we would even reach the declaration.

While we could create an exception for this case it would violate our intuitive sense that in general the point of declaration for a name is after we see the complete declaration(with some exceptions for example class member variables) with unclear benefits. Point of declaration is covered in section 3.3.2.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • I just thought about giving this answer (including a sample), but that would be the same like shadowing `i` within a `for()` loops body. The ratioale must be something else. – πάντα ῥεῖ Dec 11 '14 at 19:23
  • 2
    @πάνταῥεῖ I think the answer is more about how it wouldn't really make sense for the variable declaration to come *after* the loop body in which it is valid, not about any potential for shadowing. – cdhowie Dec 11 '14 at 19:26
  • 14
    (Especially since the body of a do...while loop executes once before the condition is even evaluated, so putting a declaration, especially one with assignment, into the loop condition really doesn't make any sense.) – cdhowie Dec 11 '14 at 19:31
  • 1
    @cdhowie Well, the unrolled sample makes it a good explanation for the rationale. – πάντα ῥεῖ Dec 11 '14 at 20:46
20

There are several reasons for why it would be difficult to allow.

The language sticks to the general rule that everything should be declared above the point of usage. In this case the variable declared in do-while would be declared below its expected natural scope (the cycle body). Making this variable accessible inside the cycle would've required a special treatment for do-while cycles. Even though we know examples of such special treatment (e.g. in-class member function bodies can see all class members, including the ones declared below), there's probably not much practical sense in doing it for do-while cycles.

In case of do-while these special treatment rules would also require finding a meaningful way of handling initialization of variables declared in this fashion. Note that in C++ language the lifetime of such variable is limited to one iteration of the loop, i.e. the variable is created and destroyed on each iteration. That means that for do-while cycle the variable will always remain uninitialized, unless you introduce some rule that would somehow move the initialization to the beginning of the loop body. That would be quite confusing in my opinion.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
8

It would be very unnatural to have a declaration of i after the block and to then be able to access it in the block. Declaration in for and while are nice short-hands that give limited-scope use to a variable that is needed in the loop logic.

Cleaner to do it this way:

int i;
do {
  i = get_data();
  // whatever you want to do with i;
} while (i != 0);
sfjac
  • 7,119
  • 5
  • 45
  • 69
5

This is because everything else follows the practice of declaring variables before you use them, eg:

public static void main(String[] args){ 
  // scope of args
}

for(int i=1; i<10; i++){
  // scope of i
}


{
...
int somevar;
//begin scope of var

...

//end of scope of var
}

This is because things are parsed top down, and because following this convention keeps things intuitive, thus why you can declare a while(int var < 10) because the scope of that var will be the area inside the loop, after the declaration.

The do while doesn't make any sense to declare a variable because the scope would end at the same time it would be checked because that's when that block is finished.

davidahines
  • 3,976
  • 16
  • 53
  • 87
0

Add this

#define do(cond) switch (cond) do default:

at the beginning of your code.

Now, you can write

do (int i = get_data()) 
{

    // your code

} while ((i = get_data()));

It is important that this #define does not break the original syntax of the do keyword in do-while loop.

However, I admit that it is obscure.

DaBler
  • 2,695
  • 2
  • 26
  • 46
-2

Your first syntax is valid while the second is not. However, your while loop will loop forever, even if your function get_data() returns 0. Not sure if that's exactly what you want to happen.

  • 1
    The question outright states one example is valid and the other isn't; the question is asking _why_ the language is specified this way. (Unlike most SO questions, this is not a "debug my code for me" question.) – Jeffrey Bosboom Feb 17 '16 at 02:19