34

My guess is it just made parsing easier, but I can't see exactly why.

So what does this have ...

do
{
  some stuff
}
while(test);

more stuff

that's better than ...

do
{
  some stuff
}
while(test)

more stuff
justinhj
  • 11,147
  • 11
  • 58
  • 104

8 Answers8

58

Because you're ending the statement. A statement ends either with a block (delimited by curly braces), or with a semicolon. "do this while this" is a single statement, and can't end with a block (because it ends with the "while"), so it needs a semicolon just like any other statement.

Joe White
  • 94,807
  • 60
  • 220
  • 330
  • Well, there is some legitimacy to the question. for(;;) {do something; } Doesn't actually end with any semicolons other than the ones that go with the contained statements. – Matthias Wandel Jun 02 '09 at 22:37
  • 12
    @Matthias: but it ends with a curly brace. – xian Jun 02 '09 at 22:38
  • And the reason that it has to be a "statement" is because a computer is putting your code together for you into a program.. the consistency isn't for the programmer's sake – ryansstack Jun 02 '09 at 22:44
  • It still seems arbitary to me whether you define the iteration statement as DO statement WHILE '(' expression ')' ';' DO statement WHILE '(' expression ')' but I suppose it is more conistent. It's basically saying you must end this with a statement but it has to be a semi colon. – justinhj Jun 02 '09 at 22:48
  • 5
    If it seems arbitory try writing the grammer without it. Since Statements can be nested you need to define a delimiter. In C/C++ this is the ';'. – Martin York Jun 03 '09 at 00:16
  • @Martin Yes I understand the need for a delimiter between statements in general, but my question is why you need it in this case. This answer merely states that you need it by definition. That's not really what I was looking for. The accepted answer gives a clear example of how you can not write a valid statement if the grammar were different. – justinhj Oct 31 '09 at 07:24
  • 7
    The accepted answer just makes a different assertion, which you intuitively accepted as "correct" and as a "clear example", while in fact it is absolutely incorrect. The problem you believe would arise "if the grammar were different", wouldn't actually arise. – AnT stands with Russia Oct 31 '09 at 21:56
31

If you take a look at C++ grammar, you'll see that the iteration statements are defined as

while ( condition ) statement

for ( for-init-statement condition-opt ; expression-opt ) statement

do statement while ( expression ) ;

Note that only do-while statement has an ; at the end. So, the question is why the do-while is so different from the rest that it needs that extra ;.

Let's take a closer look: both for and regular while end with a statement. But do-while ends with a controlling expression enclosed in (). The presence of that enclosing () already allows the compiler to unambiguously find the end of the controlling expression: the outer closing ) designates where the expression ends and, therefore, where the entire do-while statement ends. In other words, the terminating ; is indeed redundant.

However, in practice that would mean that, for example, the following code

do
{
  /* whatever */
} while (i + 2) * j > 0;

while valid from the grammar point of view, would really be parsed as

do
{
  /* whatever */
} while (i + 2)

*j > 0;

This is formally sound, but it is not really intuitive. I'd guess that for such reasons it was decided to add a more explicit terminator to the do-while statement - a semicolon. Of course, per @Joe White's answer there are also considerations of plain and simple consistency: all ordinary (non-compound) statements in C end with a ;.

Community
  • 1
  • 1
AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • You can see that the question hasn't been edited, the number of edits is shown when there are any. The question seems straightforward enough that I hope it means what I intend. The accepted answer seems superior to yours, since it shows that without the semi-colon, valid uses of the grammar become ambiguous. In your example it is merely confusing to the user. – justinhj Oct 26 '09 at 02:58
  • 3
    @justinhj: No, absolutely incorrect. The accepted answer is confusing, since it implies some "different behaviors", but fails to explain what behaviors these would be. Expectedly, as you can easily see by yourself, one of the commenters on the accepted answer got actually confused when he assumed that without semicolon requirement the inner `while` statement would get mis-associated with the outer `do`. That's simply not true. The grammar is specifically crafted not to let this happen, semicolon or not. – AnT stands with Russia Oct 26 '09 at 05:36
  • I wish the author of the accepted answer would clarify, which "different behaviors" he was implying... Without that the accepted answer is not an answer at all. – AnT stands with Russia Oct 26 '09 at 05:37
  • The different behaviour is quite clear to me. Without the semi-colon requirement you simply cannot nest a while loop inside a do-while, and this seems wrong. – justinhj Oct 31 '09 at 07:22
  • @justinhj: But that's not true. Someone told you so and you just accepted it rigth away without a single doubt. In fact, even without the semi-colon requirement (after `do-while`) you still can nest a `while` loop inside a `do-while` one and it still will be correctly associated. There's no problem in writing the language grammar that way, and in fact it is already written that way. – AnT stands with Russia Oct 31 '09 at 16:09
  • @justinhj: Also, note the comments I just added after the "accepted" aswer where I explain in more detail why it is incorrect. – AnT stands with Russia Oct 31 '09 at 16:17
  • @AndreyT "Someone told you so and you just accepted it rigth away without a single doubt." That is not the case, I spent some time satisfying myself that this is true. – justinhj Nov 03 '09 at 00:26
  • 7
    +1 for the only correct answer with a real example of something "bad" that would happen if the semicolon were not required. – R.. GitHub STOP HELPING ICE Apr 13 '11 at 00:26
  • Likewise, I can't believe the only *correct* answer is languishing down here. – caf Apr 13 '11 at 02:47
  • 3
    @Tony: AndreyT's answer doesn't purport to show an ambiguity at all - as it says, because the parantheses are required, the parse is *not* ambiguous - it is merely potentially unintuitive. – caf Apr 13 '11 at 14:09
  • @Tony: My explanation explicitly states that the expression *does* need to be enclosed in parentheses. All I'm saying is that for a human it is easy to *forget* the parentheses, while the compiler never forgets anything. This might lead to a very non-obvious errors, when the code "looks fine" to a human, but does not do what a human expects it to do. – AnT stands with Russia Apr 13 '11 at 21:11
24

It's because while statements are valid within a do-while loop.

Consider the different behaviors if the semicolon weren't required:

int x = 10;
int y = 10;

do 
  while(x > 0)
    x--;
while(x = y--);
Don
  • 777
  • 4
  • 4
  • Thanks, that seems to explain the apparent arbitrary ; – justinhj Jun 02 '09 at 23:11
  • 25
    The fact that there is no instruction between do and while would be enough for a compiler to find the difference between while "end of do" and while "new loop". Your example is interesting but i don't think it explains why there is a semicolon after do's while. – Benoît Jun 03 '09 at 06:36
  • 8
    onebyone: Not true. `do while(...);` isn't legal. An empty `do-while` loop is written like: `do ; while(...);` or `do {} while(...);` It wouldn't compile otherwise. – Mehrdad Afshari Sep 19 '09 at 15:40
  • 5
    -1. The example seems to imply that without trailing `;` requirement the code would be misinterpreted somehow. In reality, the language grammar (even in its current form) does not allow any alleged misinterpretations of the above code, even if the trailing `;` requirement is removed. Benoît is right: the example does not explain anything relevant to the question. This answer is incorrect. I allow a possibility that Don implies something that I'm missing, but until he clarifies what he meant this is a solid -1. – AnT stands with Russia Oct 31 '09 at 16:07
  • 1
    Additionally, note that C language grammar is so specifically designed that the syntactical analyser doesn't have to perform any significant look-ahead in order to recognize the current syntactical construct. This answer implies that in order to allow the proper recognition of the statement *in the body* of `do-while` the grammar needs a `;` *at the end* of `do-while`. This just doesn't make any sense. The C grammar, once again, is specifically designed to be free of such look-ahead requirements. – AnT stands with Russia Oct 31 '09 at 16:16
  • 6
    This answer is wrong - `do while (x > 0) x--;` *cannot* be misinterpreted as an empty loop with a controlling expression of `x > 0`, followed by an `x--;` statement. This is because an empty loop *must* be written as either `do ; while (expr)` or `do {} while (expr)` - the loop body must be a statement. – caf Apr 13 '11 at 02:50
  • 3
    @Steve: in C++ and C, `do while (x)` is not legal: you must use `do ; while (x)` or do { } while (x)`. Benoît and AndreyT are correct. – Tony Delroy Apr 13 '11 at 02:50
  • 2
    A better example: `do f(); while (x++) g(); while (y++) h();`. Which `while` terminates the `do`? – potrzebie Oct 26 '14 at 23:32
9

While I don't know the answer, consistency seems like the best argument. Every statement group in C/C++ is either terminated by

  1. A semicolon
  2. A brace

Why create a construct which does neither?

JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • So, why can't I do this: int testFunc(int x) return x+1; – Rocketmagnet Jun 03 '09 at 18:45
  • 6
    @Rocketmagnet, you can't allow all statements (including null statement), because "void f() ;" (function definition with a "null statement" as body) would not be different from "void f();" (function declaration only). Both look the same. Requiring a compound statement is a good thing. And anyway, a function definition isn't a statement. – Johannes Schaub - litb Sep 19 '09 at 16:36
7

Flow control statement consistency

Considering consistency...

if (expr) statement;
do statement; while (expr);
for (expr; expr; expr) statement;
while (expr) statement;

...all these flow-control constructs, end with a semicolon.

But, countering that we can note that of the block-statement forms, only do while is semicolon delimited:

if (expr) { ... }
do { ... } while (expr);
for (expr; expr; expr) { }
while (expr) { }

So, we have ';' or '}', but never a "bare" ')'.

Consistency of statement delimiters

We can at least say that every statement must be delimited by ; or }, and visually that helps us distinguish statements.

If no semicolon were required, consider:

do statement1; while (expr1) statement2; do ; while (expr2) statement3; while (expr3) statement4;

It's very difficult to visually resolve that to the distinct statements:

do statement1; while (expr1)
statement2;
do ; while (expr2)
statement3;
while (expr3) statement4;

By way of contrast, the following is more easily resolved as a ; immediately after a while condition tells you to seek backwards for the do, and that the next statement is unconnected to that while:

do statement1; while (expr1); statement2; do ; while (expr2); statement3; while (expr3) statement4;

Does it matter, given people indent their code to make the flow understandable? Yes, because:

  • people sometimes make mistakes (or have them transiently as the code's massaged) and if it visually stands out that means it will be fixed more easily, and
  • macro substitutions can throw together lots of statements on one line, and we occasionally need to visually verify the preprocessor output while troubleshooting or doing QA.

Implications to preprocessor use

It's also worth noting the famous preprocessor do-while idiom:

#define F(X) do { fn(X); } while (false)

This can be substituted as follows:

if (expr)
    F(x);
else
    x = 10;

...yields...

if (expr)
    do ( fn(x); } while (false);
else
    x = 10;

If the semicolon wasn't part of the do while statement, then the if statement would be interpreted as:

if (expr)
    do-while-statement
; // empty statement
else
    x = 10;

...and, because there are two statements after the if, it's considered complete, which leaves the else statement unmatched.

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
3

C is semicolon-terminated (whereas Pascal is semicolon-separated). It would be inconsistent to drop the semicolon there.

I, frankly, hate the reuse of the while for the do loop. I think repeat-until would have been less confusing. But it is what it is.

Nosredna
  • 83,000
  • 15
  • 95
  • 122
1

My answer is that, the compiler may get confusion, when we didn't include the semicolon in the termination of do.....while(); loop. Without this it is not clear about:

  1. when the do ends?
  2. If the while may a separate loop followed immediately after do loop.

That's why we include semicolon in the end of do......while loop, to indicate the loop is terminating here if the condition is false.

Flexo
  • 87,323
  • 22
  • 191
  • 272
Anusha
  • 11
  • 1
1

In C/C++ whitespace don't contribute to structure (like e.g. in python). In C/C++ statements must be terminated with a semicolon. This is allowed:

do
{
  some stuff; more stuff; even more stuff;
}
while(test);
lothar
  • 19,853
  • 5
  • 45
  • 59