51

In many languages (a wide list, from C to JavaScript):

  • commas , separate arguments (e.g. func(a, b, c)), while
  • semicolons ; separate sequential instructions (e.g. instruction1; instruction2; instruction3).

So why is this mapping reversed in the same languages for for loops:

for ( init1, init2; condition; inc1, inc2 )
{
    instruction1;
    instruction2;
}

instead of (what seems more natural to me)

for ( init1; init2, condition, inc1; inc2 )
{
    instruction1;
    instruction2;
}

?

Sure, for is (usually) not a function, but arguments (i.e. init, condition, increment) behave more like arguments of a function than a sequence of instructions.

Is it due to historical reasons / a convention, or is there a good rationale for the interchange of , and ; in loops?

6
  • 1
    (My f1rst post here. I am not sure whether this question belongs more to Programmers or SO, so feel free to migrate, if it is needed.) Commented Apr 21, 2013 at 21:23
  • 9
    This is definitely a Programmers post. Welcome! :-) Commented Apr 21, 2013 at 21:49
  • 1
    "Why Not" will provide the answer - by having the same answer - "Because someone needed to make a choice, and that is the choice they made" Same as "Why did they choose "{" and "}" and 1000 other choices they made - "Because".
    – mattnz
    Commented Apr 21, 2013 at 22:41
  • 2
    @mattnz The question is about consistency (not "Why we use ; not |?" (or Why do we use 'else' not 'otherwise'?)) which is not case for one language, but a big number of them. An answer that e.g. "it was made in C as a shorthand for while loop (and multiple statements for inc were thought only later), and people didn't want to change it to avoid programmers' irritation" would be perfectly fine. Commented Apr 21, 2013 at 22:48
  • I recall reading - perhaps in in K&R - that the comma operator was originally added to the language in order to make it possible to initialize more than one variable in the init-expression of a for statement.
    – zwol
    Commented Apr 22, 2013 at 2:19

7 Answers 7

18

So why in the same languages such mapping is reversed for for loops.

Technically, the mapping is not "reversed".

  • The things separated by commas are not parameters. In (at least) C++ and Java, they can be declarations, so they are not even expressions.
  • The things separated by semicolons are not (single) statements either.

In reality what we have here is a different syntactic context where the same symbols are being used differently. We are not comparing like with like, so there is no mapping, and no strong argument for a consistent mapping based on semantic consistency.

So why not do it the other way around?

Well I think the reasons come from the "natural" meaning of , and ;. In English written language, a semicolon is "stronger" break than a comma, and the glyph for semicolon is more visible than a comma. Those two things combine to make current arrangement seem (to me!) to be more natural.

But the only way to know for sure why the syntax choice was made would be if the C designers could tell us what they were thinking back in ~1970. I doubt that they have a clear memory of technical decisions made that far back in time.


Is it due to historical reasons / a convention

I'm not aware of any language before C that used a C-like syntax for "for" loops:

  • Donal Fellows notes that BCPL and B didn't have an equivalent construct.

  • The FORTRAN, COBOL and Algol-60 (and Pascal) equivalents were less expressive, and had syntaxes that did not resemble C "for" syntax.

But languages like C, C++ and Java that came after C all clearly borrow their "for" syntax from C.

10
  • So, the philosophy of (, vs ;) is (weaker vs stronger break), rather than (tuple- vs sequence-splitter), right? Still for me it is not obvious whether arguments or statements need stronger breaks (as in many cases for a sequence of statements, breaks are implicit (see e.g. JavaScript (e.g. i++[line break]j++))), but at least now I get the point why the current convention is not "obviously reversed". Commented Apr 21, 2013 at 23:39
  • @PiotrMigdal the comma as a delimiter would prevent the use of the comma operand and might imply the components of the for loop are statements rather than expressions. This has significant implications.
    – user40980
    Commented Apr 22, 2013 at 0:04
  • The last comment made me curious what BCPL did, but apparently there it was FOR i = e1 TO e2 BY e3 DO c (e1..e3 expressions, c command), which more closely resembles BASIC's syntax. Source
    – user
    Commented Apr 22, 2013 at 7:41
  • 1
    @PiotrMigdal - The "philosophy" is whatever K&R and the rest were thinking back in 1970. I don't think it went to the depth of thinking that you imagine. (They were trying to implement a "higher level" language to avoid having to write masses of telephone switch software in assembler.)
    – Stephen C
    Commented Apr 22, 2013 at 7:46
  • I just checked; the for syntax was introduced in C (it wasn't in B or BCPL). Commented Apr 22, 2013 at 10:16
60

We write loops like:

 for(x = 0; x < 10; x++)

The language could have been defined so that loops looked like:

 for(x = 0, x < 10, x++)

However, think of the same loop implemented using a while loop:

 x = 0;
 while(x < 10)
 {
     x++;
 }

Notice that the x=0 and x++ are statements, ended by semicolons. They aren't expressions like you would have in a function call. Semicolons are used to separate statements, and since two of the three elements in a for loop are statements, that's what is used there. A for loop is just a shortcut for such a while loop.

Additionally, the arguments don't really act like arguments to a function. The second and third are repeatedly evaluated. It's true they aren't a sequence, but they also aren't function arguments.

Also, the fact that you can use commas to have multiple statements in the for loop is actually something you can do outside the for loop.

x = 0, y= 3;

is a perfectly valid statement even outside of a for loop. I don't know of any practical use outside the for loop though. But the point is that commas always subdivide statements; it's not a special feature of the for loop.

9
  • Sure, I understand that "while" loop is "more fundamental". But such "short-hand notation" does not make much sense (at least to me), as you could start with x = 0; y = 0; and (inside the curly bracket) x++; y++;... Commented Apr 21, 2013 at 21:42
  • 2
    @PiotrMigdal, oh you could. My point is that the pieces inside the for loop are statements (which are separated by semicolons) not expressions (which are separated by commas) Commented Apr 21, 2013 at 21:44
  • 1
    I get the difference, just for me ; is natural for a sequence of statements, not necessarily separating any statements (so is it just that tastes differ?). And in the current convention one occasionally ends up with separating sequences of statements with commas anyway... Commented Apr 21, 2013 at 22:14
  • 3
    @PiotrMigdal, members of structs/unions are seperated by semicolons, but those aren't really sequential. So its certainly not restricted to a sequence of statement in its use. At the end of the day, syntax does rather come down to taste. Commented Apr 21, 2013 at 22:18
  • I don't know of any practical use outside the for loop though --- How about (foo)?bar++, qux++:bletch --- Where you want the ?: expression to do two things rather than just one. The return value if foo is true is qux, but both bar and qux get incremented.
    – user40980
    Commented Apr 21, 2013 at 23:14
15

In C and C++ this is the comma operator, not just a comma.

The grammar for a for loop is something like

for ([pre-expression]; [terminate-condition]; [increment-expression]) body-expression

In the case of your question:

pre-expression -> init1, init2
terminate-condition -> condition
increment-expression -> inc1, inc2

Note that the comma-operator allows you to perform multiple actions in one statement (as the compiler sees it). If your suggestion was implemented there would be an ambiguity in the grammar as to when the programmer intended to write a comma-operator statement or a separator.

In short, ; signifies the end of a statement. A for loop is a keyword followed by a list of optional statements surrounded by (). The comma-operator statement allows the use of , in a single statement.

4
  • 3
    A for loop is a set of expressions separated by semicolons. Statements can be much more than expressions - one can't slip a case statement or if statement into a for loop parts. It is a significant implication to say that the components of the for loop are statements when one looks at the bnf form of a for loop
    – user40980
    Commented Apr 22, 2013 at 0:02
  • @MichaelT: But in C++ the syntax of a for loop explicitly allows a statement (declaration) as its first part. (C++ allowed declarations mid-function, as opposed to its predecessor C89). You can't generalize such statements across languages, even for 2 languages as close as C and C++.
    – MSalters
    Commented Apr 22, 2013 at 8:50
  • @MichaelT Did you miss the 'is something like' part?
    – James
    Commented Apr 22, 2013 at 9:21
  • @James you can avoid the "something like" by using the actual bnf of for ( {<expression>}? ; {<expression>}? ; {<expression>}? ) <statement> for C and for ( for-init-statement; conditionopt ; expressionopt ) statement for C++ --- The ';' does not only signify a statement terminator. A for loop is not followed by statements enclosed in ().
    – user40980
    Commented Apr 22, 2013 at 13:53
8

There is no conceptual reversal.

Semicolons in C represent more major divisions than commas. They separate statements and declarations.

The major divisions in the for loop is that there are three expressions (or a declaration and two expressions) and a body.

The commas you see in C for loops are not part of the syntax of the for loop specifically. They are just manifestations of the comma operator.

Commas are major separators between arguments in function calls and between parameters in function declarations, but semicolons are not used. The for loop is special syntax; it has nothing to do with functions or function calls.

2

Maybe this is something specific for C/C++, but I post this answer, because the syntax of the lagnuages you described is mostly influenced by the C-Syntax.

Besides the previously answered questions are true, from a technical point of view, that's also because in C (and C++) the comma is actually an operator, that you can even overload. Using a semicolon-operator (operator;()) would possibly make it harder to write compilers, since the semicolon is the axiomatic expression terminator.

What makes this intersting is the fact, that the comma is widely used as seperator all over the language. It seems like the comma operator is an exception, that is mainly used to get for-loops with multiple conditions working, so what's the deal?

In fact the operator, is built to do the same thing like in definitions, argument lists, and so on: It has been build to seperate expressions - something the syntactic construct , cannot do. It can only seperate what has been defined in the standard.

However the semicolon does not seperate - it terminates. And this is also what leads us back to the original question:

for (int a = 0, float b = 0.0f; a < 100 && b < 100.0f; a++, b += 1.0f)
    printf("%d: %f", a, b);

The comma seperates the expressions in the three loop parts, whereas the semicolon terminates a part (initialization, condition or afterthought) of the loop definition.

Newer programming languages (like C#) may not allow overloading the comma-operator, but they most likely kept the syntax, because changing it feels somehow unnatural.

1
  • There's a problem with this argument. In a for statement the ; symbol is plainly used as a separator. It separate the 3 syntactic parts of the statement. There is not 3rd semicolon to "terminate" the progressive expression list. It is terminated by a different token - ).
    – Stephen C
    Commented Apr 26, 2013 at 0:08
0

For me they are used more less similar meaning to their linguistic sense. Commas are used with lists and semicolons with more separate parts.

In func(a, b, c) we have a list of arguments.

instruction1; instruction2; instruction3 is maybe a list but a list of separate and independent instructions.

While in for ( init1, init2; condition; inc1, inc2 ) we have three separate parts - a list of initializations, a condition and a list of increment expressions.

0

The easiest way to see it is the following:

for(x = 0; x < 10; x++)

is:

for(
x = 0;
x < 10;
x++
)

In other words, those x = 0 thingy is actually a statement/instructions rather than a parameter. You insert a statement there. Hence they are separated by semicolon.

In fact there is no way they are separated by comma. When do the last time you insert things like x<10 as a parameter? You do that if you want to computer x<10 once and insert the result of that operation as parameter. So in comma world you would put x<10 if you want to pass on the value of x < 0 to a function.

Here you specify that the program should check x<10 every time the loop is passed. So that's an instruction.

x++ is definitely another instructions.

Those are all instructions. So they are separated by semi colon.

6
  • It isn't a statement. It is an expression separated by a semicolon. A statement is completely different.
    – user40980
    Commented Apr 22, 2013 at 4:49
  • x < 10 may be an expression (which would usually be separated by semicolon. x=0 is definitely a statement/instructions.
    – user4951
    Commented Apr 22, 2013 at 4:52
  • Look at the bnf for C - if the for loop was statements, one could use other statements such as another for switch or return inside the for loop definition (ie for(int i = 0; if(i > 1024) { return; } ; switch (i % 3) { case 0; case 1: i++; case 2: i++; } ) { ... }) --- you can't. It isn't a statement. Instead it is defined as for ( {<expression>}? ; {<expression>}? ; {<expression>}? ) <statement>
    – user40980
    Commented Apr 22, 2013 at 4:57
  • Strange. int i =0 is an expression all right, but we do it mainly to declare an int namely i and assign 0 to it (it also returns 0 but as a side effect. You can't do for({int i=0;j=i};j<0;cout << "Hello world") can you? Or yea I think you can.
    – user4951
    Commented Apr 22, 2013 at 5:18
  • 1
    @JimThio: You're probably not aware of it, but "statement" and "expression" have very precise meanings in language standards. int i = 0 definitely is NOT an expression. The set of rules describing an expression is fairly complex, considering what can constitute an expression, but the construct TYPE NAME = EXPRESSION matches none of those rules.
    – MSalters
    Commented Apr 22, 2013 at 8:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.