89

This (note the comma operator):

#include <iostream>
int main() {
    int x;
    x = 2, 3;
    std::cout << x << "\n";
    return 0;
}

outputs 2.

However, if you use return with the comma operator, this:

#include <iostream>
int f() { return 2, 3; }
int main() {
    int x;
    x = f();
    std::cout << x << "\n";
    return 0;
}

outputs 3.

Why is the comma operator behaving differently with return?

xyz
  • 3,349
  • 1
  • 23
  • 29

4 Answers4

147

According to the Operator Precedence, comma operator has lower precedence than operator=, so x = 2,3; is equivalent to (x = 2),3;. (Operator precedence determines how operator will be bound to its arguments, tighter or looser than other operators according to their precedences.)

Note the comma expression is (x = 2),3 here, not 2,3. x = 2 is evaluated at first (and its side effects are completed), then the result is discarded, then 3 is evaluated (it does nothing in fact). That's why the value of x is 2. Note that 3 is the result of the whole comma expression (i.e. x = 2,3), it won't be used to assign to x. (Change it to x = (2,3);, x will be assigned with 3.)

For return 2,3;, the comma expression is 2,3, 2 is evaluated then its result is discarded, and then 3 is evaluated and returned as the result of the whole comma expression, which is returned by the return statement later.


Additional informations about Expressions and Statements

An expression is a sequence of operators and their operands, that specifies a computation.

x = 2,3; is expression statement, x = 2,3 is the expression here.

An expression followed by a semicolon is a statement.

Syntax: attr(optional) expression(optional) ; (1)

return 2,3; is jump statement (return statement), 2,3 is the expression here.

Syntax: attr(optional) return expression(optional) ; (1)

Community
  • 1
  • 1
songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • 1
    good explanation. But are there some practical applications ? or just errors to be done? – Jean-François Fabre Sep 07 '16 at 07:59
  • 7
    @Jean-FrançoisFabre IMO it's just confusing, not useful at all. – songyuanyao Sep 07 '16 at 08:00
  • 11
    I've seen it once or twice used in `for` loops when, bizarrely, it can make code *clearer* in numerical calculations. – Bathsheba Sep 07 '16 at 08:05
  • @prakharsingh95 I tried to add more explanations, is it clear enough now? – songyuanyao Sep 07 '16 at 08:12
  • 6
    @Jean-FrançoisFabre: like Bathesheba says, it's so that you can write something like `i += 1, j += 2` in a for loop. Someone decided that the C++ grammar (or rather the C grammar, since this part was copied from there) is complicated enough already without trying to define that the precedence of comma is higher than assignment when you write `x = 2, 3` but lower when you write `x = 2, y = 3`! – Steve Jessop Sep 07 '16 at 15:07
  • @SteveJessop Precedence of comma is *lower* when you write `x = 2, 3`. If comma had a higher precedence it would have been equivalent to `x = (2, 3)`, which would have meant `x = 3`. – xyz Sep 07 '16 at 16:16
  • @prakharsingh95: Yes, exactly. It would be difficult/complicated to make the precedence of comma higher just in that case, while retaining the useful fact that it's lower in the case of multiple assignments in a for loop separated by commas. – Steve Jessop Sep 07 '16 at 16:23
  • You could demonstrate this with `x = (2,3);` – Daniel Sep 07 '16 at 20:15
  • @Steve Jessop: I’d say that the whole problem stems from the idea to treat the comma as an operator rather than a separator. Imagine what had happened if they had the idea of treating the semicolon as operator as well. How has the precedence to look like to make both `{ … ; … }` and `for(…;…;…) …; ` work as expected… – Holger Sep 08 '16 at 12:26
  • 2
    @Holger: Semicolon terminates a statement, it isn't an operator. This is something the answer could be tweaked to make more clear. "x = 2 , 3" is an expression with 2 operators, and for reasons of supporting for(;;), = has higher precedence. (As everyone else said.) But "return 2, 3;" is a statement that contains the expression "2, 3". There isn't *technically* a precedence to the keyword "return". (Although *effectively*, since it's part of the statement that accepts the expression, it is parsed last -- lower "precedence" than any operator *in* the expression.) – Micha Berger Sep 08 '16 at 14:56
  • @Micha Berger: you didn’t get the point. The comma is an operator, because it was a deliberate decision of the C language designer that `,` is an operator. This causes `return 2 , 3` to be valid, without an actual purpose (talking about `C` without operator overloading). The desire to be able to write `x=4, y=5` rather than `x=4; y=5;` is only justified at two places, declarations and `for` loops. So look, e.g. at Java, where comma is not an operator, but just allowed to be used at declarations and `for` loops, the way you would expect it, without allowing these funny abuses ala `return 2, 3`. – Holger Sep 08 '16 at 15:08
  • 1
    @Holger: No, I got that. I was just saying the answer would do better if it made the difference between a statement and an expression more explicit. Then the comment chain wouldn't have the question about precedence of "," vs ";" -- since ";" terminates a statement -- and thus any expressions in it -- and is not part of the expression. Then you can talk about "(x=2), 3;" vs "return (2, 3);" in terms of "=" having a higher precedence verses a return statement taking an expression. – Micha Berger Sep 08 '16 at 17:13
  • @MichaBerger You cannot treat return as an operator ever. Because then you could write `(return 3), y = 4;`, meaning, *return 3* , then *update y to 4*, which violates the obvious requirement that **return must be the last executed statement**. From what I understand, this is why `return ` will **always** be `return ()`. – xyz Sep 20 '16 at 11:07
  • 1
    @prakharsingh95 - Thanks for the vehement agreement. – Micha Berger Sep 20 '16 at 11:16
  • @MichaBerger I am always polite. No offense meant. – xyz Sep 20 '16 at 16:21
  • 2
    @prakharsingh95 -- I just meant there must have been a miscommunication. You repeated my point in a tone like you disagreed. To quote what I wrote, "Then you can talk about '(x=2), 3;' vs 'return (2, 3);' in terms of '=' having a higher precedence verses a return statement taking an expression." But in any case, when I wrote that the distinction wasn't yet in the answer. It was since added, so perhaps that's what threw you off. – Micha Berger Sep 20 '16 at 18:33
  • @xyz, pointing out that you can actually put statements after a return, despite them not being able to be reached. – Kröw Mar 26 '23 at 23:27
32

The comma (also known as the expression separation) operator is evaluated from left to right. So return 2,3; is equivalent to return 3;.

The evaluation of x = 2,3; is (x = 2), 3; due to operator precedence. Evaluation is still from left to right, and the entire expression has the value 3 with the side-effect of x assuming the value of 2.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • 2
    Can you please edit and elaborate more on *expression separation operator*? Like I mentioned in a comment on @songyuanyao's answer, I can understand why `return 2,3` and `return (2,3)` are the same. I believed the former should be `(return 2),3`. – xyz Sep 07 '16 at 08:11
  • @BiagioFesta explains that part well. – Bathsheba Sep 07 '16 at 08:26
  • 1
    @prakharsingh95 `return 2` is a statement (like e.g. those formed by `for,while,if`), not an expression. You can't write e.g. `f(return 2)` or `2+return 2`. So, `(return 2),3` is syntactically invalid. – chi Sep 07 '16 at 17:05
  • @chi Yes, you are correct. I meant I was expecting `return 2, 3` to be **interpreted** as `(return 2), 3`. – xyz Sep 07 '16 at 17:07
  • @prakharsingh95 You expected it to be interpreted as an invalid piece of program code? :) – Yakk - Adam Nevraumont Sep 07 '16 at 19:41
  • @Yakk no, I meant I expected it to return 2 and drop 3. – xyz Sep 07 '16 at 19:46
  • @prakharsingh95 expecting return 2, 3 to be interpreted as (return 2), 3 is expecting return (a statement) to be considered as an expression. Since return is a statement it could never be parsed in a way which would require it to be an expression. – eques Sep 07 '16 at 20:16
  • 2
    @prakharsingh95 according to the grammar of C++, `return` can only occur in the following cases: (a) `return` *expression_opt* `;`, and (b) `return` *braced-init-list* `;` . – M.M Sep 08 '16 at 04:23
20

This statement:

  x = 2,3;

is composed by two expressions:

> x = 2
> 3

Since operator precedence, = has more precedence than comma ,, so x = 2 is evaluated and after 3. Then x will be equal to 2.


In the return instead:

int f(){ return 2,3; }

The language syntax is :

return <expression>

Note return is not part of expression.

So in that case the two expression will be evaluated will be:

> 2
> 3

But only the second (3) will be returned.

BiagioF
  • 9,368
  • 2
  • 26
  • 50
  • 2
    UV'd. Very picky, but would be nice if you marked `` as explicitly optional (from a grammar perspective). – Bathsheba Sep 07 '16 at 08:27
  • 2
    There are 5 expressions in the parse tree of `x=2,3`. Both literals `2` and `3` are at the bottom of the parse tree, as is the identifier `x`. These are all individually valid expressions. Operator precedence means that `=` occurs _lower_ in the parse tree, and combines the two expressions `x` and `2` into the fourth expression `x=2`. Finally, the fifth expression is formed by the comma operator joining its two sides `x=2` and `3`. However, you incorrectly state that operator precedence determines the _order_ of evaluation. It doesn't. The order of evaluation is determined by sequencing rules. – MSalters Sep 07 '16 at 08:59
  • 2
    I voted up for mentioning that return isn't part of an expression – Daniel Jour Sep 07 '16 at 14:02
  • @MSalters I agree with you, but I just incorrectly used the word "*because*", instead of "*since*". Something my English is not so perfect! ;-= – BiagioF Sep 07 '16 at 14:22
  • @BiagioFesta: Actually, _because_, _since_ and _so_ are all words which in English signal a causal relation. And leaving such words out might not be enough to stress that there is _no_ causal relation between two statements. Since we're often writing for inexperienced people here, we should be **explicit** when two statements are unrelated (i.e. in this case, we should be explicit that the precedence order is unrelated to the evaluation order) – MSalters Sep 07 '16 at 14:29
  • 2
    Is "macro-expression" a technical term here? It seems a bit confusing to use it when "macro expressions" in the sense of preprocessor stuff also exist. – senshin Sep 08 '16 at 04:57
2

Try to apply the simplistic approach just highlighting the precedence with parenthesis:

( x = 2 ), 3;

return ( 2, 3 );

Now we can see the binary operator "," working in the same way on both, from left to right.

Luciano
  • 2,695
  • 6
  • 38
  • 53
  • 1
    The tricky part is realizing that the `x = 2, 3` is itself an expression ,while for `return` it's `return ` . So you read them as `(x = 2, 3)` and `(2, 3)`. – xyz Sep 15 '16 at 14:03