22

In C++ you are allowed to have an empty condition inside the for-loop, for example as in for (;;) or for (int x = 0;; ++x). But you can't do while ().

When condition is omitted inside the for loop, condition is assumed to be true (so the loop loops forever). Why isn't this the case with while loops, that is, what's the argument behind not letting while () be an alias of while (true)?

Not a bug
  • 4,286
  • 2
  • 40
  • 80
Luka Mikec
  • 417
  • 4
  • 20
  • 8
    The answer is likely 2-fold: 1) to be backwards compatible with C99, and 2) because the standards committee said so. There may be some grammar reason why `while()` may not work, but theoretically that could have been fixed if they really wanted it to be. – Zac Howland Feb 11 '14 at 20:59
  • 2
    @ZacHowland 1) Then the question is why this is the case in C99 ;) – leemes Feb 11 '14 at 21:00
  • 2
    @leemes - Because the C90 standards committee said so ;) – Zac Howland Feb 11 '14 at 21:01
  • 2
    This question isn't opinion based, the OP is asking if there exists a reason for this oddity. The answer is either "yes: because X", or "not really". One is true, and the other is false. What's subjective about that? – Mooing Duck Feb 11 '14 at 21:01
  • @MooingDuck "What is the argument behind not letting `while()` be an alias of `while(true)`?" - that is opinion based as there isn't really an argument for it - it just is. – Zac Howland Feb 11 '14 at 21:03
  • @ZacHowland: He asked "Why is it the case", and the answer is probably "Because the C90 standards committee said so, there isn't any argument for it", which is not subjective at all. – Mooing Duck Feb 11 '14 at 21:06
  • It is mandated by design of the C language, see my post – Nikos Athanasiou Feb 11 '14 at 21:28
  • 1
    `#define while(c) for(;c;)` That should "fix" it ;) (jk, will not even work correctly) – leemes Feb 11 '14 at 22:37

6 Answers6

29

Presumably, it's a side-effect of the fact that each given clause within the for-statement is optional. There's reasons why some for-loops wouldn't need an assignment; there's reasons why some others wouldn't need a condition; there's reasons why still others wouldn't need an increment. Requiring there to be some minimum number of them would be needlessly-added complexity.

Sneftel
  • 40,271
  • 12
  • 71
  • 104
  • This answers why `for(;;)` is valid, but does not address why `while()` cannot be (which likely would be opinion based). – Zac Howland Feb 11 '14 at 21:06
  • 1
    The point is that they didn't set out to make conditions optional in control statements in general. It was purely a matter of consistency within the special case of the for-loop. – Sneftel Feb 11 '14 at 21:17
  • @ZacHowland the only reason to make `while()` work without a condition would be to express the common idiom of an endless loop (or ended by jumping out). Since `for(;;)` already expresses that idiom, there's no need to change the syntax for `while()`. – Jon Hanna Feb 11 '14 at 23:24
  • There are at least 3 interpretations of my question, one would be what the Standard says (6.8.5.3); was there and if yes what was (historically) the reason behind this decision in the Standard of C (of course, the historical reason for inclusion in C++ (not C) Standard is backward compatibility); and is there a good argument for these design decisions regardless of whether that argument also historically made designers of langague have them included. Since the third seems to me to be the most important, and Sneftel's answer is very strong, convincing and intuitive, I accept this answer. – Luka Mikec Feb 12 '14 at 15:12
8

The following is from the book Deep C Secrets:

Early C had no separate operators for & and && or | and ||. (Got that?) Instead it used the notion (inherited from B and BCPL) of "truth-value context": where a Boolean value was expected, after "if" and "while" and so forth, the & and | operators were interpreted as && and || are now; in ordinary expressions, the bitwise interpretations were used. It worked out pretty well, but was hard to explain. (There was the notion of "top-level operators" in a truth-value context.)

So there you have it, while() would set the context for a truth value and can't be empty or implied for the same reason if() can't be empty, the mechanics of the early language expected them not to be.

Nikos Athanasiou
  • 29,616
  • 15
  • 87
  • 153
  • 3
    I don't get it. What does the meaning of the operators, and the "context" have to do with the question if the expression is *optional*? – leemes Feb 11 '14 at 21:49
  • To implement the 'truth-value-context' in C (as in B and BCPL) a boolean value was expected after if() and while() ... so they can't be empty. Even though the original reason (dissambiguation of the meaning of & as & or && etc) is not present anymore, the design was passed on to newer versions of C and then to C++. – Nikos Athanasiou Feb 11 '14 at 21:59
  • 3
    Still don't get why this is an argument. They could said that **if** there is something within the parentheses, it's a boolean expression context. Also, why doesn't the same count for `for` loops? – leemes Feb 11 '14 at 22:10
  • Yes they could but they didn't, that's what a design choice is. You don't need to understand anything there, don't trouble yourself. I simply present the history of it, which explains what the original reasons where to have a boolean value expected after `while()` and `if()`. The case of `for` differs in that there are 3 contexes present "declaration - truth value - ammendment", not a single one. – Nikos Athanasiou Feb 11 '14 at 22:24
8

In C++ you are allowed to have an empty condition inside the for-loop ... what's the argument behind not letting while() be an alias of while(true)?

First of all, C++ (and C# and many other languages) are the way they are for backwards compatibility with C, so let's talk about C.

Let's make some statements and draw a conclusion.

  1. There is a good reason why the for loop allows you to omit the condition.
  2. The same good reason applies to the while loop.
  3. The while loop does not allow the condition to be omitted; it is inconsistent.
  4. Consistency of design choices across statements is an important factor in the design of C.
  5. Therefore there must be an unobvious good reason for the inconsistency; there must be a good reason why the while loop is inconsistent with the for loop.

And now the question is "what is that unobvious good reason?"

But the question only makes sense if the chain of logic described above is correct, which it is not. Of those statements, only #3 is actually true! The for loop in C is a poor design; it's redundant, confusing for novices and its lexical conventions are inconsistent with the rest of the language. It provides almost zero additional representational power to the language over a straightforward while loop.

There is no answer to your question; the correct response is rather to reject the premise of the question entirely. The for loop only seems reasonable because it's a 40+ year old misfeature that most of us grew up with, so its quirks are second nature now; this is familiarity, not good design. Had we grown up without the for loop, we wouldn't be adding it.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 1
    And yet recently, range-based for-loops *were* added, indicating a distinct appetite for a loop designed to express iteration over a sequence. Its semantics may be a bit hairy, but I think that's more a matter of the limitations of C's ability to abstract sequences than it is of the advisability of including the feature in general. – Sneftel Feb 13 '14 at 19:53
  • 1
    @Sneftel: Oh don't get me wrong; I love the idea of a loop that abstracts over the operation of iterating over a sequence. The fundamental problem with the `for` loop is that its syntax is *so goofy*. The semicolon can logically be thought of as the *sequential composition of side effects operator*. When you say `A(); B(); C();` in C, that means to sequentially compose the side effects of the three function calls. That's what it means everywhere except in a foreach loop, where it means something very different. – Eric Lippert Feb 13 '14 at 20:03
  • That's a good point. It would be interesting if they had made the syntax `for(a)(b)(c) { ... }`, or even `for {a}{c}(b) {...}`. After all, `a` and `c`, in a sense, deserve to be blocks, and `b` deserves not to be. – Sneftel Feb 13 '14 at 20:30
  • 1
    @Sneftel: That would be a start. The braces though would be confused with scopes which is unfortunate. I say use awesome invention called words to improve clarity. By simply replacing `;` with words we get much clarity. How about `do (initializer while expression by statement) statement` -- `do (node* p = head while p != NULL by p = p->next;)...`. is in the spirit of C syntax without overloading the meaning of `;`. – Eric Lippert Feb 13 '14 at 22:24
3

I think the main difference is between expressions and statements.

Sure, in C the two aren't rigorously distinguished, but I would say the for loop is:

for (statement; expression; statement) {
    ...
}

The expression is a boolean expression, while the statements are...statements which have side effects. Of course, C isn't semi-functional; you can put side effects in the middle expression, but it isn't idiomatic.

Yet sometimes you don't want an expression, but statements at the beginning and at each loop iteration is useful, so the middle expression is optional:

// Infinite counter
int i;
for (i = 0;;i++) {
   ...
}

This by definition means that the expression is considered always true

On the other hand, while and if can only take expressions. There is nothing very useful left (unlike the two useful statements left) if you omit that expression: nobody would write

// Idiot coding
if (true) {
   ...
}

because the point of an if statement is to check whether some unknown is true or not!

Same thing with while. The point of while is to do something over and over as long as a condition in the form of an expression is true. It's kinda like an "iterated if". This is why

while() {
   ...
}

is not considered logical and thus not allowed.

ithisa
  • 752
  • 1
  • 8
  • 25
1

As per the Document :

6.8.5.3 The for statement

The statement for ( clause-1 ; expression-2 ; expression-3 ) statement behaves as follows:

  1. The expression expression-2 is the controlling expression that is evaluated before each execution of the loop body. The expression expression-3 is evaluated as a void expression after each execution of the loop body. If clause-1 is a declaration, the scope of any identifiers it declares is the remainder of the declaration and the entire loop, including the other two expressions; it is reached in the order of execution before the first evaluation of the controlling expression. If clause-1 is an expression, it is evaluated as a void expression before the first evaluation of the controlling expression.158)
  2. Both clause-1 and expression-3 can be omitted. An omitted expression-2 is replaced by a nonzero constant.

So, in case of for loop, condition will be replaced by non-zero constant and no such implementation for while loop.

Not a bug
  • 4,286
  • 2
  • 40
  • 80
  • OP wanted to know the reasons behind this text from the Standard; I assume he already knows C/C++ syntax – anatolyg Feb 12 '14 at 11:18
  • Right. And the original question was basically, why is an omitted conditional allowed in the second expression of a for-statement, but not in the condition of a while-statement? He already knows the rules, he wanted to know the reasoning used by the people writing those words you copied. – Sneftel Feb 12 '14 at 11:53
-3

The difference between logical statements used in while() and for(;;) loops is that:

  • in case of for the statement defines condition of exiting the loop

  • in case of while() the statement defines condition of executing the loop

Assuming that, you see that to enter a loop, you need at least a condition of executing, not a condition of exiting.

mekkanizer
  • 722
  • 2
  • 9
  • 28
  • 3
    `for` loop's syntax contains a condition for executing the loop, just like the `while` loop's syntax – anatolyg Feb 12 '14 at 11:15