When we think of the comma character we often think of it as a separator. It separates values in an CSV file, it separates items in lists, it may separate index values in multidimensional arrays (in other languages) and more. But in C++ an obscure way of using them was as an operator. The reason it never made it big as an operator and into the typical programming psyche is that largely it is seen as useless or some kind of “syntactic sugar”. So in this article we try to show how it works, why it has a stigma and some possible uses for it that may prove useful at some point in your career going forward. Worst case scenario it provides fodder for your geek parties and may even snag you that lady you have had your eye on for awhile.
The straight forward to think of it is as an operator that has two operands. Much like + or / or * would have in some kind of arithmetic. The two operands are evaluated but the second one is the only one that is actually assigned. Here is an example…
// i is assigned the value 7. int i = (5,7);
The above code assigns the value 7 to the variable “i”. It sees the left operand (in this case 5) and evaluates it, but its result is thrown away. It then evaluates the right operand and its value is used to complete the assignment. Ok, what is this twisted and demented C++ voodoo all about? Why would anyone want to put in the work of having a left hand operator that has its value thrown away when they really want the operand on the right? This is the first question usually asked and it is perfectly reasonable to think that. This is the stigma that usually follows this operator. The second thing you might be thinking is what is with the parenthesis here? They simply serve to support operator precedence. That is, the assignment operator has greater precedence than the comma operator. If we didn’t have the parenthesis we would have int i = 5,7; and the 5 would be assigned to “i” and then you would get some syntax error for having this ,7 hanging off of it. Chain this comma operator together with others and it will work as expected, yielding the last result… int i = (5, 6, 7); // i is now 7. Here 5 and 6 are evaluated, 6 is returned, it is evaluated with 7 and then 7 is assigned to “i”.
Well it has a few edge cases that involve things like brevity of if statements (which will show in a second) and also the use of side effects. Generally side effects are bad in programming. We don’t want our code to go doing things we didn’t initially intend them to do. To show you one way this may work is to use our increment operator as seen below…
int a = 3; int b = 4; // i will be assigned 4, but "a" was incremented and now is 4. int i = (a++,b);
Taking this one step further what if the second operand uses the first one? We want the second to evaluate to a result and use the operand from the first, but only after we did something to it.
int a = 3; int b = 4; // i will be assigned 8. "a" was still changed permanently. // "a" was incremented, then the second value was evaluated with the new value of "a" being used. int i = (a++,a + b);
If you think about it a little bit you can see this same thing can be accomplished in two statements. First increment “a” and then assign i to the value of a + b. From a programming best practice I always advise against this sort of syntax if it even can be remotely considered confusing. Why make things more difficult for others to maintain your code?
Sure, this can be used right in condition statements for loops or if statements etc. Let’s throw it into a while loop and an if statement see what we get…
int a = 0;
int b = 4;
while (a++,b < 10) { b += 1; } // a will end up being 7 while b will be 10. cout << "a is: " << a << " and b is: " << b << endl; // a is now 3 and since 2 is less than 3, it will print the statements. if (a = 3,2 < a) { cout << "a is: " << a << endl; } // After the if statement, a is still going to be 3. [/cpp] Our last example is going to show you how this might be used to shorten up a code block and get rid of the need for some curly braces. The example below shows how we can assign to values to variables in a single line and since it is a single line we use it in an if without the need for curly braces. [code] int a = 0; int b = 7; // Single line if statement doing two assignments if (a == 0) a = 2, b=4; // Here "a" will now be 2 and "b" will be 4. cout << "a is: " << a << " and b is: " << b << endl; [/code] It is things like this that make C++ such a fascinating language to play with. My hopes is that next time you see a comma you don't take it for granted just as something that separates items, but that it can be an operator in its own right. However, just because you can use it this way doesn't mean you should except for the special cases where it can really help. Out of all my years programming with C++ I never really truly found a solid reason to use it. Sure it can save a few characters or lines but I often prefer to be explicit when I can. The main goal that we all should strive for besides solution correctness is that we also provide solutions that are easy to read, understand and maintain. I find that is often best done using separate statements or assignments. Thanks for reading! 🙂