48

I have been programming in C and C++ for a few years and now I'm just now taking a college course in it and our book had a function like this for an example:

int foo(){
  int x=0;
  int y=20;
  return x,y; //y is always returned
}

I have never seen such syntax. In fact, I have never seen the , operator used outside of parameter lists. If y is always returned though, then what is the point? Is there a case where a return statement would need to be created like this?

(Also, I tagged C as well because it applies to both, though my book specifically is C++)

Justin Ethier
  • 131,333
  • 52
  • 229
  • 284
Earlz
  • 62,085
  • 98
  • 303
  • 499
  • 1
    It'd make more sense if it was `return x++, y++;` or something like that. – Frank V Mar 29 '10 at 16:15
  • 14
    What book is this from? I can't imagine any legitimate reason for doing this. – Stephen Mar 29 '10 at 16:16
  • I notice while taking a class in C, you can get away with writing a non-void function without a return statement. All you get is a warning. IIRC, whatever is left on top of the stack is returned. Which could be anything, not necessarily the last statement like in Ruby. I would suspect that the same thing is happening here, the x is pushed on the stack and then the y. The y being the last item on the stack, so it is returned. – sanscore Mar 29 '10 at 16:16
  • 7
    "D. Malik, C++ Programming: Program Design Including Data Structures, Fourth Edition. Course Technology Incorporated, 2007, ISBN 1-4188-3640-0" I do not recommend it for anyone because the writer does not appear to have a firm grasp of C++ mentioning things like "variable declarations always go to the top of the function no matter what." – Earlz Mar 29 '10 at 16:19
  • 124
    Throw the book away. – Daniel Daranas Mar 29 '10 at 16:20
  • 1
    Also, the example "good" code is littered with things like in my example. always using non-trivial variable names for simple constants. That code there was taking straight out of the book except for the function name was `FunctionReturnN4` – Earlz Mar 29 '10 at 16:22
  • 3
    @Daniel, I really wish I could but it's required to get my college credits – Earlz Mar 29 '10 at 16:22
  • 5
    @Frank V: Even that wouldn't make sense - the variables are going out of scope. @Earlz: is it at all possible that this is merely intended to demonstrate that this does *not* return two values? Giving an example of what not to do? – Cascabel Mar 29 '10 at 16:29
  • Seems like this should have been part of a bug-finding exercise in the book. – Andrew Jaffe Mar 29 '10 at 16:30
  • 1
    @Jefromi, yes, it is a what not to do but the book wasn't all that explicit about it and it had like 2 pages covering this topic. It basically said "this won't return two values, it will only return the last in the list." but didn't give a reason as to why I would ever need such syntax(the comma operator was never discussed in the book up til now) and it didn't tell me how to actually return two values. (hadn't covered structs/classes yet) – Earlz Mar 29 '10 at 16:33
  • It does not make sense. It looks very much like a typo. – AndyUK Mar 29 '10 at 16:51
  • @Earlz: You don't need structs/classes to return two values. You can also return by reference. – Brian Mar 29 '10 at 16:55
  • @Brian, well of course, but thats not really "returning" two values. That is passing in two values to be modified by the function – Earlz Mar 29 '10 at 17:17
  • @Earlz- I had to use the previous edition of that book in one of my courses. You have my deepest sympathies. – bta Jun 24 '10 at 19:40
  • 2
    Speaking as Mr. Picky, you never saw the `,` operator used inside parameter lists. Inside a parameter list, the comma has a much different meaning. – David Thornley Jun 24 '10 at 19:51
  • 1
    @bta thank you. Sadly have to use it for my next semester too :( – Earlz Jun 24 '10 at 21:22
  • This is used in the Python C source code. See the macro definitions in Include/boolobject.h. `#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True` is the example. In this case, there is a reference count increment performed and `Py_True` is returned. – Phillip Cloud Jan 04 '13 at 08:36
  • +1 for pun on 'point' – Jordan Jun 22 '13 at 00:47
  • Funny how: int x=0, y=0; x,y=foo(); // would seem to "work" for the code creator lol :-) – franckspike Nov 07 '17 at 21:15

18 Answers18

53

According to the C FAQ:

Precisely stated, the meaning of the comma operator in the general expression

e1 , e2

is "evaluate the subexpression e1, then evaluate e2; the value of the expression is the value of e2." Therefore, e1 had better involve an assignment or an increment ++ or decrement -- or function call or some other kind of side effect, because otherwise it would calculate a value which would be discarded.

So I agree with you, there is no point other than to illustrate that this is valid syntax, if that.

If you wanted to return both values in C or C++ you could create a struct containing x and y members, and return the struct instead:

struct point {int x; int y;};

You can then define a type and helper function to allow you to easily return both values within the struct:

typedef struct point Point;

Point point(int xx, int yy){
  Point p;
  p.x = xx;
  p.y = yy;
  return p;
}

And then change your original code to use the helper function:

Point foo(){
  int x=0;
  int y=20;
  return point(x,y); // x and y are both returned
}

And finally, you can try it out:

Point p = foo();
printf("%d, %d\n", p.x, p.y);

This example compiles in both C and C++. Although, as Mark suggests below, in C++ you can define a constructor for the point structure which affords a more elegant solution.


On a side note, the ability to return multiple values directly is wonderful in languages such as Python that support it:

def foo():
  x = 0
  y = 20
  return x,y # Returns a tuple containing both x and y

>>> foo()
(0, 20)
Community
  • 1
  • 1
Justin Ethier
  • 131,333
  • 52
  • 229
  • 284
  • 1
    Your `point` struct needs a constructor taking two `int` parameters. – Mark Ransom Jun 24 '10 at 19:49
  • @Mark - The `struct` is just an example - that said, would you care to elaborate? Strictly speaking, there are no constructors in C. Regardless, the code compiles just fine in C and C++, and the `x` and `y` members may be directly accessed by code. – Justin Ethier Aug 05 '11 at 01:00
  • In C you're right, no constructor is possible. In C++ a constructor lets you do `return point(x,y);`. Sorry for being so cryptic. – Mark Ransom Aug 05 '11 at 02:01
  • 1
    I wanted to point out that your point to make a point when there was no point amused me. – Jason Rice Jan 02 '15 at 04:08
23

The comma in parameter lists is just there to separate the parameters, and is not the same as the comma operator. The comma operator, as in your example, evaluates both x and y, and then throws away x.

In this case, I would guess that it is a mistake by someone who tries to return two values, and didn't know how to do it.

Thomas Padron-McCarthy
  • 27,232
  • 8
  • 51
  • 75
20

The comma operator is primarily used in for statements like so:

for( int i=0, j=10; i<10; i++, j++ )
{
    a[i] = b[j];
}

The first comma is not a comma operator, it's part of the declaration syntax. The second is a comma operator.

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
Joel
  • 5,618
  • 1
  • 20
  • 19
  • 18
    This makes no sense. Why is this answer upvoted, and why is this picked as the right one! Its completely irrelevant to the question asked. – vivekian2 Aug 04 '11 at 22:49
  • In that case, use of the comma is required to increment both `i` and `j`. There are other instances where you might use the comma instead of a semicolon if you want to emphasize that both statements are really tightly linked and shouldn't be split. For instance `std::memcpy(data, moredata, moresize), datasize+=size;`. I like to kep the statements together to avoid someone accidentally moving or erasing the second part. – André Caron Aug 05 '11 at 14:23
  • 1
    @Joel: There are badges to earn if you take back upvoted/accepted answers. – Sebastian Mach Mar 06 '12 at 10:46
  • 2
    I took the question behind the question to be "Why have a comma operator?" rather than "Why have one in a return statement?" Apparently the OP agreed that was his real question. – Joel Mar 06 '12 at 18:01
9

This doesn't really answer the original question at all but might be of interest to some people, but if you wanted to it to return both in C++ you'd need to write it like this (and would need a c++0x compiler)

tuple<int, int> foo()
{
    int x = 0;
    int y = 20;
    return make_tuple(x, y);
}

The access it like this -

tuple<int, int> data = foo();
int a = get<0>(data);
int b = get<1>(data);
jcoder
  • 29,554
  • 19
  • 87
  • 130
8
 struct Point {
   int x, y;
   Point(int x_) : x(x_), y(0) {}
   Point(const Point& p) : x(p.x), y(p.y) {}
   Point operator, (int y_) const { Point p=*this; p.y = y_; return p; }
 };

 Point get_the_point () {
    int x = 0;
    int y = 20;
    return (Point)x, y;
 }

:p

kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
  • 4
    That's so not C++. I mean, it'll compile, but that's so unreadable. Ick. – clahey Mar 29 '10 at 16:42
  • 1
    @clahey: Then you will hate this: http://www.boost.org/doc/libs/1_42_0/libs/assign/doc/index.html – kennytm Mar 29 '10 at 16:50
  • 6
    I think the boost stuff is definitely questionable, but there's something worse about what you have there. For example: "return (Point)1, 2, 3;" returns (1,3). "return (Point)1" returns (1,0). Neither of those feels like intuitive behavior. Also, your notation doesn't save anything. If you just declare a proper constructor that takes two ints, you can just write "return Point(x, y);" It doesn't save even a single character of typing and is more readable. The boost stuff at least saves a lot of typing. – clahey Mar 29 '10 at 17:14
  • 2
    @clahey: Note that I'm not advocating this style (see the ":p"?), I'm just showing there maybe a "point" that a comma operator is abused (I can't place a multi-line comment). – kennytm Mar 29 '10 at 17:48
  • That is so wonderfully *evil*. Is there an equivalent of the IOCCC for C++? – John Bode Mar 29 '10 at 20:25
5

Much like everyone commenting here thinks it is pointless and I don't disagree, just looking at the example, I'm going to make a guess that's not much better:

The writer was getting a compiler warning about x not being used within the function, and this was an easy way to get the warning to go away.

Joel Rondeau
  • 7,486
  • 2
  • 42
  • 54
  • I just tried this with g++, and there is a warning if you use -Wall. I'm not sure whether to praise the author for compiling code before putting it in the book or condemn the author for coming up with this solution. Although, it might have been interesting if the author had actually used this as an opportunity to talk about compiler warnings and such. – clahey Mar 29 '10 at 16:46
  • I take it back. I just tried the code as given and that still gives a warning. Maybe he's on a different compiler. – clahey Mar 29 '10 at 16:48
  • He also has a book on Java(a red flag right there) so probably using MVC++ – Earlz Mar 29 '10 at 17:22
  • Seemed VS6.0 would be the likely candidate and it does give a warning C4189 : local variable is initialized but not referenced if the "x," is removed, provided warnings are set to level 4 (highest). – Joel Rondeau Mar 29 '10 at 18:29
  • If that was the author's intent, it was a bad idea... writing code that looks like it returns two values when it fact it only returns one is going to do more harm than good. – Jeremy Friesner Sep 26 '10 at 03:56
4

This syntax can be used to save additional scope brackets of an if- statement. E.g. normally you would write the following:

if (someThing == true)
{
    a = 1;
    b = 2;
    return true;
}

This can be replaced by the following:

if (someThing == true)
    return a = 1, b = 2, true;

I think the usage of this coding style is rather motivated by the urge for posing than for writing clean code.

florg
  • 63
  • 4
  • Heh. that's an... interesting use case – Earlz Jul 27 '12 at 00:53
  • I don't think that the motivation for this normally comes from he urge to pose, but rather from the wish to improve the readability of the code by over time saving the reader hours of vertical scrolling work – Kaiserludi Aug 21 '13 at 17:30
4

This is the comma operator (,).

Both expressions x and y are evaluated. The result of the overall expression is y, i.e., the latter value.

It's hard to say why it is used here. I guess, for demonstration purposes. Clearly the function could be refactored to:

int foo()
{
  return 20;
}
Daniel Daranas
  • 22,454
  • 9
  • 63
  • 116
3

That looks like a terrible example of code. It might be valid syntax in C/C++, but I can't think of a reason why you'd ever want to do that.

If you want to return both x and y, a better way to do it in C++ would be to define a "Point" class or struct with x and y properties, and return that. Another option would be to pass in x and y by reference, then set the values appropriately in the method.

If the method is going to just return y, I would just "return y;". If x needs to be "evaluated" before the return statement, it should be done on a separate line.

Andy White
  • 86,444
  • 48
  • 176
  • 211
2

There is no point in that return statement.

If x were declared volatile, it would force an access (since at least in C++ references to volatile variables are considered to be externally observable behavior), but it isn't.

If, instead of x, there was some sort of calculation with side effects, it would do that calculation and then return y. However, a non-volatile x has no side effects. The implementation is not required to execute any code that has no side effects or externally observable behavior. The comma operator executes whatever is on the left side of the comma, disregards the result, and executes and keeps the value of the right side (except that it's free to ignore the left side of the operator in this case).

Therefore, the return x, y; statement is the exact same thing as return y;. If x wasn't just a completely meaningless thing to execute, it would be stylistically better to write it as x; return y;, which is the precise same thing. It wouldn't be nearly as confusing that way.

David Thornley
  • 56,304
  • 9
  • 91
  • 158
  • And even if `x` is replaced by some expression with side effects, there's no point in shoving it into the return statement like that. Just make it a separate statement: `expr_with_side_effects; return y;`. – Keith Thompson Aug 05 '11 at 19:47
  • Usually: Yes, reads much clearer. But what about constexpr functions (before C++14)? – DaveFar Oct 30 '16 at 22:12
1

On the one hand, it could be an honest mistake on the part of the writer.

On the other hand, the writer might be explaining syntactically correct correct code, versus compiler warnings.

Either way, the only way to return multiple results would be to define a class and use its instance, or perhaps an array or collection.

Olaseni
  • 7,698
  • 16
  • 44
  • 68
1

This is the comma operator. Such syntax can be used to disable warning from compiler about unused variable x.

osgx
  • 90,338
  • 53
  • 357
  • 513
1

Outside of for loops the other major user of this comman operator (as apposed to the function call version) is in macros that return a value after doing some stuff. These are other ways to do this now, but I think that the comman operator used to be the cleanest way.

#define next(A, x, y, M) ((x) = (++(y))%(M) , A[(x)])

Please note that this macro is a bad example of macros in general because it repeats x and probably for other reasons. Use of the comma operator in this fashion should be rare. The example from your book was probably an attempt to make a code exampe fit within the number of lines available for that example.

nategoose
  • 12,054
  • 27
  • 42
0

I have seen this syntax used in C to do housekeeping when returning midway in an operation. Definitely not maintainable code:

int foo(int y){
  char *x;
  x = (char*)malloc(y+1);
  /** operations */
  if (y>100) return free(x),y;
  /** operations */
  if (y>1000) return free(x),y;

}
SRC
  • 435
  • 4
  • 5
0

The book is trying to eliminate potential confusion of people who learned other languages before C++. In many languages, you can return multiple values using similar syntax. In C++, it will compile without warning (unless you specify -Wall or -Wunused-value), but it won't work the way you might expect if you were accustomed to those other languages. It will just return the last value.

However, it seems the author caused more confusion than he prevented, since there's no readable situation to use such syntax in a return statement in C++ except by accidentally using it like another language. He's warning about usage that wouldn't occur to most people to try. If you did, though, it would be super confusing to debug, since the multiple assignment statement int x, y = foo() also compiles just fine.

Bottom line: always use -Wall and fix what it warns you about. C++ syntax allows you to write many things that don't make sense.

Karl Bielefeldt
  • 47,314
  • 10
  • 60
  • 94
0

When used with the return keyword, the comma operator returns the last value, which is initially confusing but can make things more concise.

For example, the following program will exit with a status code of 2.

#include <iostream>
using namespace std;

void a() {
    cout << "a" << endl;
}


int one() {
    cout << "one" << endl;
    return 1;
}

int zero() {
    cout << "zero" << endl;
    return 0;
}

int main() {
    return one(), a(), zero(), 2;
}

When compiling and executing with the following, you will see the output below.

michael$ g++ main.cpp -o main.out && ./main.out ; echo $?
one
a
zero
2
magnus
  • 4,031
  • 7
  • 26
  • 48
0

Is there a case where a return statement would need to be created like this?

IMO, I would never use multiple returns in a function like the book example. It violates structured design. Nevertheless, there are many programmers that do! Debugging someone else's code I have assigned a value to a global variable in each return statement so I could figure out which return executed.

0

If y is always returned though, then what is the point?

The point is the side effect of x (ie of the left hand side of the comma operator). See e.g. Justin Ethier answer for details.

Is there a case where a return statement would need to be created like this?

An example is for a constexpr function in C++11 until C++14: such a function may not contain arbitrary statements, but exactly one return statement.

Here is a code sample from Patrice Roys “The Exception Situation" at CppCon 2016:

constexpr int integral_div(int num, int denom) {
    return assert(denom != 0), num / denom;
}
DaveFar
  • 7,078
  • 4
  • 50
  • 90