<p>In many C style languages the <code>,</code> binary operator takes 2 expressions and simply returns the second one:</p>
<pre class="lang-js prettyprint-override"><code>let a = (12, 42);
console.log(a);
// Output 42
</code></pre>
<p>This is quite useful, but many new languages don't have it. So I'm wondering if there is something wrong with it why my language shouldn't have it.</p>

<language-design><operators><c>
Advantages/disavantages of including the comma operator?
CC BY-SA 4.0
2023-08-09T21:34:47.290Z
The main disadvantage of the comma operator in C is that it is easily confused with the use of commas to separate arguments in a function call.
Chris Dodd
<p>In C and similar languages, <code>,</code> is used to separate expressions, while <code>;</code> is used to separate statements. In these languages, expressions and statements are different things, so it makes sense to have different separators for them.</p>
<p>In many new languages, e.g. Rust, almost everything is an expression. So you can use a single separator (usually <code>;</code>) to separate everything. <code>12, 42</code> in C is equivalent to <code>{ 12; 42 }</code> in Rust.</p>

CC BY-SA 4.0
2023-05-17T03:15:18.827Z
2023-05-17T03:15:18.827Z
alephalpha
CC BY-SA 4.0
2023-08-09T21:39:48.180Z
This is usually referred to as ISWIM or ML syntax as they were the first languages to use it, as far as I know.
Chris Dodd
<p>It's useful to have operators that will unconditionally evaluate both arguments and then unconditionally yield the left one, or unconditionally yield the right one.  The comma-operator syntax used in C may not be optimal for this, however.  There are at least three variations on such constructs for which I can see some real uses:</p>
<ol>
<li><p>Perform the left, then perform the right, then yield the value of the right operand.</p>
</li>
<li><p>Perform both operations in either order, and then yield the right operand (if the surrounding code needs it, which it wouldn't in most cases).</p>
</li>
<li><p>Perform the left, then perform the right, then yield the value that had been produced by the left operand.</p>
</li>
</ol>
<p>I'm not sure what syntax I'd favor for those operations, but I see no reason for the language to have a nicer syntax for the first than for the others.</p>

CC BY-SA 4.0
2023-08-09T20:17:51.950Z
2023-08-09T20:17:51.950Z
supercat
CC BY-SA 4.0
2024-12-01T10:56:45.183Z
I concur with the usefulness. To choose which form is better, consider something that is nearly equivalent but much less controversial: the statement separator `;`. Ideally you want `printf("Hello"); x = 42` to be consistent with `printf("Hello"), x = 42`.
G. Sliepen
CC BY-SA 4.0
2024-12-22T22:49:02.420Z
@G.Sliepen: Having a construct begin with something that identifies what follows as two expressions which should be processed in one of the means described above would be different from the ; statement separator, but I don't see that as being a bad thing.  Such constructs are a bit unusual, so having them seem unusual would be entirely reasonable.
supercat
<p>I think the only time I've used the comma operator is in <code>for</code> statements:</p>
<pre><code>for (x=1,y=2,z=3;  x&lt;17;  ++x,y*=2,z/=2) { … }
</code></pre>
<p>This is at least semi-useful (having all the iteration adjustments together, inside the <code>for</code>).<br />
But other uses seem to be more confusing than useful.</p>

CC BY-SA 4.0
2023-08-10T00:23:59.743Z
2023-08-10T00:23:59.743Z
Ray Butterworth
CC BY-SA 4.0
2023-08-10T13:33:00.313Z
Some languages with C-style `for` loops specially allow the "initialiser" and "step" parts to be comma-separated lists of expressions, when the language itself doesn't have a comma operator for expressions in general. E.g. [Java does this](https://docs.oracle.com/javase/specs/jls/se19/html/jls-14.html#jls-14.14.1).
kaya3
<p>I don't know how much the comma operator is used in practice for this, but surely one of the original intended purposes would have been to assign an intermediary variable to avoid repeating common sub-expressions, or to avoid awkward placement or excessive nesting.</p>
<p>This would have been in-keeping with the design goal of C of having a fairly general mathematical expression facility, and certainly avoiding repetition would have been even more important before optimising compilers.</p>
<p>For example (using an arbitrary formula):</p>
<pre><code>result = m=(x+1)*y, (m*2)+(1/m);
</code></pre>
<p>True enough, it's not difficult to spread over more lines as separate statements in this context, but for complicated scientific formulas which should be treated as a unit, it provides a neat solution, particularly on a greenscreen terminal where there wasn't the luxury of vertical space.</p>
<p>In conjunction with the facility it provides for multiple operations to occur (such as multiple assignment) in a context where there can be only a single statement, it's not hard to see what the advantage was at the time.</p>

CC BY-SA 4.0
2024-12-13T13:23:03.280Z
2024-12-13T13:23:03.280Z
Steve
CC BY-SA 4.0
2024-12-18T07:17:43.310Z
Wouldn’t you need to declare the variable anyway, meaning that this wouldn’t reduce the number of statements?
xigoi
CC BY-SA 4.0
2024-12-18T11:04:58.993Z
@xigoi, in K&R C, you have to declare on a separate line to assignment anyway, but you can also roll up multiple variable declarations (of the same type) in a comma-separated list, like: `int m, p, q, r;`. It was also common practice at the time to reuse declared variables (i.e. to assign them two or more times), rather than giving every unique value a separate variable, so combining declaration and assignment was seen as less useful back then than it is seen today.
Steve
CC BY-SA 4.0
2024-12-18T15:04:21.237Z
@xigoi, actually just clarifying a point in my previous comment, it wasn't that the initialiser syntax didn't exist in K&R, it was that all declarations had to be made at the beginning of the block before other statements, so it was impossible to use the initialiser syntax to assign a calculated value that was only produced midway through the block.
Steve
CC BY-SA 4.0
2024-12-22T22:52:03.233Z
@Steve: I think early compilers required that a compiler know how much space to allocate for a stack frame via "subtract" instruction which precedes any other executable code.  Initialization syntax which only works with constants could easily allow a compiler to use a "block move" to perform intiializations.
supercat
<p>Leaving aside the design problems with the choice of operator punctuation, there are a few reasons I'd like to have such an operator (or, as supercat correctly notes, a family of sequencing operators.)</p>
<p>First, many languages make a syntactic distinction between expressions and statements. C# for example has many contexts in which statements are not allowed but expressions are, and if the only way you have to represent &quot;evaluate this expression for its side effects then evaluate this expression for its value&quot; is to create two statements, then you cannot express that logic using the (often more elegant) expression context. Suppose we had an operator SEQ; which is nicer?</p>
<pre><code>int UpdatedCount { DownloadLatestData(); return this.count; }
int UpdatedCount =&gt; DownloadLatestData() SEQ this.count;
</code></pre>
<p>It's a small difference in this example but these small differences add up.</p>
<p>Second, the C# compiler internally does have sequencing operators; they are very helpful as intermediate lowerings en route to generating code. Similar to <code>goto</code> -- what is good for the compiler team is likely also useful for the user.</p>
<p>And more generally, it's more pleasant to write a spec for a language when you can say precisely what a high-level feature desugars to in terms of lower-level language features, rather than describing the semantics of an operator that is in the compiler implementation but not in the language being compiled.</p>

CC BY-SA 4.0
2024-12-30T19:22:15.057Z
2024-12-30T19:22:15.057Z
Eric Lippert
<h1>Readability</h1>
<p>The main problem programmers have with the comma operator is this would permit having multiple expressions in a single line, which is generally frowned upon.</p>
<pre><code>x = 10;
y = 20;
z = 30;
if (a) {
    b();
}
</code></pre>
<p>Vs:</p>
<pre><code>if (x = 10, y = 20, z = 30, a) {
    b();
}
</code></pre>
<h1>Better alternatives</h1>
<p>If a language would add the ability to perform expressions <em>'inline'</em> in other expressions with the comma operator, they could just have <a href="https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html" rel="noreferrer">statement expressions</a> which perform the same task but are more powerful, as they can include statements instead of just expressions. Example:</p>
<pre><code>int x = ({
    int y = 8;
    if (z) {
        f();
        y += 10;
    }
    y;
});
</code></pre>

CC BY-SA 4.0
2023-05-16T18:17:20.023Z
2023-05-16T18:17:20.023Z
CPlus
CC BY-SA 4.0
2023-08-09T20:47:11.717Z
Are you suggesting that your "Better alternative" is more readable than the version with the comma operator?
Barmar
CC BY-SA 4.0
2023-08-10T01:16:58.093Z
@Barmar Not really. I am saying that it's more capable, which is objectively the case, because GCC-style blocks can handle statements such as `for` and variable declarations but comma operators can only handle expressions.
CPlus
<p>The comma operator is easy to confuse with the syntax for generating lists. Even in the example you gave, one could easily think that <code>a</code> is a sequence of some sort containing 12 and 42, rather than just 42.</p>
<p>In fact, in Python (and probably some other languages), <code>a = 12, 42</code> does exactly that.</p>

CC BY-SA 4.0
2023-05-18T02:00:10.173Z
2023-05-18T02:00:10.173Z
pppery
CC BY-SA 4.0
2023-07-22T14:13:53.973Z
It's also easily confused with the syntax for separating arguments, so you need double parentheses: `func((a=12, 42))`
Barmar
<p>The benefit of the comma operator is that it allows you to include a sub-expression for its side-effects only. In languages without a comma operator, there are often ways around this ─ suppose <code>f</code> is an expression you want to evaluate just for its side-effects, and then <code>g</code> is the expression whose value you actually want:</p>
<ul>
<li>In languages with list or tuple literals, you can write <code>[f, g][1]</code>.</li>
<li>In languages with logical operators permitting it, you can write <code>(f || true) &amp;&amp; g</code>, or (more cryptically) <code>f &amp;&amp; g</code> or <code>f || g</code> when <code>f</code>'s truthiness is constant.</li>
<li>In languages with <code>let</code>-<code>in</code> expressions, you can write <code>let _ = f in g</code>.</li>
<li>In most cases, you can define a function like <code>comma(f, g)</code> which just returns <code>g</code>.</li>
</ul>
<p>So the comma operator does not really add expressiveness to the language, it just allows you to write this kind of expression explicitly instead of using an idiom. On the other hand, this kind of expression is rarely needed in real code written by humans; personally, I only use JavaScript's comma operator in Code Golf challenges or to simulate <code>let</code>-<code>in</code> expressions like <code>(x=f, g)</code> when compiling to JavaScript.</p>
<p>Also, including the comma operator like this may mean less syntax space is available for other things. For example, in Python, <code>(f, g)</code> or <code>f, g</code> are expressions which create a tuple, so they can't also mean something else.</p>
<p>The comma operator would also be almost entirely superfluous in languages where expressions cannot have side-effects, such as pure functional languages ─ the first operand would only matter if it was eagerly evaluated but <a href="https://en.wikipedia.org/wiki/Divergence_(computer_science)" rel="nofollow noreferrer">diverged</a>. (Haskell's <code>seq</code> behaves like this, and is <a href="https://stackoverflow.com/q/12687392/12299000">considered harmful</a> by some.)</p>

CC BY-SA 4.0
2023-05-16T18:20:01.450Z
2024-12-12T22:34:43.410Z
2024-12-12T22:34:43.410Z
kaya3
CC BY-SA 4.0
2024-12-11T01:21:38.247Z
"the first operand would only matter if it was eagerly evaluated but diverged." I don't understand what you mean by divergence here.
Karl Knechtel
CC BY-SA 4.0
2024-12-12T22:34:31.300Z
@KarlKnechtel A computation is said to [diverge](https://en.wikipedia.org/wiki/Divergence_(computer_science)) if it does not complete normally; it might complete abruptly (throwing an exception, terminating the program, etc.) or it might fall into an infinite loop.
kaya3
CC BY-SA 4.0
2023-08-09T16:47:29.523Z
Regarding using a function `comma(f,g)`, or more precisely, function argument evaluation, in some languages the order of evaluation is not specified, but the comma operator evaluates left to right.
Pablo H
CC BY-SA 4.0
2023-08-09T20:45:24.363Z
It tends to be used in C when you have places that only allow one expression, like the parts of a for-loop header. It's also frequently used in JS with `reduce()` along with short-form arrow functions, so you don't have to write a multi-statement function body.
Barmar
CC BY-SA 4.0
2023-05-17T16:43:30.230Z
It's not *entirely* superfluous in non-strict pure functional languages if it behaves like [seq](https://wiki.haskell.org/Seq). It would still be a strange design choice, though.
James Martin
# Advantages/disavantages of including the comma operator?
Posted by: username_0 on 2023-05-16
In many C style languages the , binary operator takes 2 expressions and simply returns the second one:
let a = (12, 42);
console.log(a);
// Output 42

This is quite useful, but many new languages don't have it. So I'm wondering if there is something wrong with it why my language shouldn't have it.
**Tags:** language-design operators c
> **Comments:**
> **username_1**: The main disadvantage of the comma operator in C is that it is easily confused with the use of commas to separate arguments in a function call.  
---
## 8 answers
### Answer by username_6 on 2023-05-16. Score: 18
The benefit of the comma operator is that it allows you to include a sub-expression for its side-effects only. In languages without a comma operator, there are often ways around this ─ suppose `f` is an expression you want to evaluate just for its side-effects, and then `g` is the expression whose value you actually want:

* In languages with list or tuple literals, you can write `[f, g][1]`.
* In languages with logical operators permitting it, you can write `(f || true) && g`, or (more cryptically) `f && g` or `f || g` when `f`'s truthiness is constant.
* In languages with `let`-`in` expressions, you can write `let _ = f in g`.
* In most cases, you can define a function like `comma(f, g)` which just returns `g`.

So the comma operator does not really add expressiveness to the language, it just allows you to write this kind of expression explicitly instead of using an idiom. On the other hand, this kind of expression is rarely needed in real code written by humans; personally, I only use JavaScript's comma operator in Code Golf challenges or to simulate `let`-`in` expressions like `(x=f, g)` when compiling to JavaScript.

Also, including the comma operator like this may mean less syntax space is available for other things. For example, in Python, `(f, g)` or `f, g` are expressions which create a tuple, so they can't also mean something else.

The comma operator would also be almost entirely superfluous in languages where expressions cannot have side-effects, such as pure functional languages ─ the first operand would only matter if it was eagerly evaluated but [diverged](https://en.wikipedia.org/wiki/Divergence_(computer_science)). (Haskell's `seq` behaves like this, and is [considered harmful](https://stackoverflow.com/q/12687392/12299000) by some.)
> **Comments:**
> **username_15** (2023-05-17): It's not *entirely* superfluous in non-strict pure functional languages if it behaves like [seq](https://wiki.haskell.org/Seq). It would still be a strange design choice, though.  
> **username_14** (2023-08-09): Regarding using a function `comma(f,g)`, or more precisely, function argument evaluation, in some languages the order of evaluation is not specified, but the comma operator evaluates left to right.  
> **username_11** (2023-08-09): It tends to be used in C when you have places that only allow one expression, like the parts of a for-loop header. It's also frequently used in JS with `reduce()` along with short-form arrow functions, so you don't have to write a multi-statement function body.  
> **username_13** (2024-12-11): "the first operand would only matter if it was eagerly evaluated but diverged." I don't understand what you mean by divergence here.  
> **username_6** (2024-12-12): @KarlKnechtel A computation is said to [diverge](https://en.wikipedia.org/wiki/Divergence_(computer_science)) if it does not complete normally; it might complete abruptly (throwing an exception, terminating the program, etc.) or it might fall into an infinite loop.  
---
### Answer by username_10 on 2023-05-16. Score: 13
Readability
The main problem programmers have with the comma operator is this would permit having multiple expressions in a single line, which is generally frowned upon.
x = 10;
y = 20;
z = 30;
if (a) {
    b();
}

Vs:
if (x = 10, y = 20, z = 30, a) {
    b();
}

Better alternatives
If a language would add the ability to perform expressions 'inline' in other expressions with the comma operator, they could just have statement expressions which perform the same task but are more powerful, as they can include statements instead of just expressions. Example:
int x = ({
    int y = 8;
    if (z) {
        f();
        y += 10;
    }
    y;
});
> **Comments:**
> **username_11** (2023-08-09): Are you suggesting that your "Better alternative" is more readable than the version with the comma operator?  
> **username_10** (2023-08-10): @Barmar Not really. I am saying that it's more capable, which is objectively the case, because GCC-style blocks can handle statements such as `for` and variable declarations but comma operators can only handle expressions.  
---
### Answer by username_12 on 2023-05-18. Score: 10
The comma operator is easy to confuse with the syntax for generating lists. Even in the example you gave, one could easily think that `a` is a sequence of some sort containing 12 and 42, rather than just 42.

In fact, in Python (and probably some other languages), `a = 12, 42` does exactly that.
> **Comments:**
> **username_11** (2023-07-22): It's also easily confused with the syntax for separating arguments, so you need double parentheses: `func((a=12, 42))`  
---
### Answer by username_2 on 2023-05-17. Score: 8
In C and similar languages, `,` is used to separate expressions, while `;` is used to separate statements. In these languages, expressions and statements are different things, so it makes sense to have different separators for them.

In many new languages, e.g. Rust, almost everything is an expression. So you can use a single separator (usually `;`) to separate everything. `12, 42` in C is equivalent to `{ 12; 42 }` in Rust.
> **Comments:**
> **username_1** (2023-08-09): This is usually referred to as ISWIM or ML syntax as they were the first languages to use it, as far as I know.  
---
### Answer by username_3 on 2023-08-09. Score: 2
It's useful to have operators that will unconditionally evaluate both arguments and then unconditionally yield the left one, or unconditionally yield the right one. The comma-operator syntax used in C may not be optimal for this, however. There are at least three variations on such constructs for which I can see some real uses:

1. Perform the left, then perform the right, then yield the value of the right operand.
2. Perform both operations in either order, and then yield the right operand (if the surrounding code needs it, which it wouldn't in most cases).
3. Perform the left, then perform the right, then yield the value that had been produced by the left operand.

I'm not sure what syntax I'd favor for those operations, but I see no reason for the language to have a nicer syntax for the first than for the others.
> **Comments:**
> **username_4** (2024-12-01): I concur with the usefulness. To choose which form is better, consider something that is nearly equivalent but much less controversial: the statement separator `;`. Ideally you want `printf("Hello"); x = 42` to be consistent with `printf("Hello"), x = 42`.  
> **username_3** (2024-12-22): @G.Sliepen: Having a construct begin with something that identifies what follows as two expressions which should be processed in one of the means described above would be different from the ; statement separator, but I don't see that as being a bad thing.  Such constructs are a bit unusual, so having them seem unusual would be entirely reasonable.  
---
### Answer by username_5 on 2023-08-10. Score: 2
I think the only time I've used the comma operator is in for statements:
for (x=1,y=2,z=3;  x<17;  ++x,y*=2,z/=2) { … }

This is at least semi-useful (having all the iteration adjustments together, inside the for).
But other uses seem to be more confusing than useful.
> **Comments:**
> **username_6** (2023-08-10): Some languages with C-style `for` loops specially allow the "initialiser" and "step" parts to be comma-separated lists of expressions, when the language itself doesn't have a comma operator for expressions in general. E.g. [Java does this](https://docs.oracle.com/javase/specs/jls/se19/html/jls-14.html#jls-14.14.1).  
---
### Answer by username_7 on 2024-12-13. Score: 0
I don't know how much the comma operator is used in practice for this, but surely one of the original intended purposes would have been to assign an intermediary variable to avoid repeating common sub-expressions, or to avoid awkward placement or excessive nesting.
This would have been in-keeping with the design goal of C of having a fairly general mathematical expression facility, and certainly avoiding repetition would have been even more important before optimising compilers.
For example (using an arbitrary formula):
result = m=(x+1)*y, (m*2)+(1/m);

True enough, it's not difficult to spread over more lines as separate statements in this context, but for complicated scientific formulas which should be treated as a unit, it provides a neat solution, particularly on a greenscreen terminal where there wasn't the luxury of vertical space.
In conjunction with the facility it provides for multiple operations to occur (such as multiple assignment) in a context where there can be only a single statement, it's not hard to see what the advantage was at the time.
> **Comments:**
> **username_8** (2024-12-18): Wouldn’t you need to declare the variable anyway, meaning that this wouldn’t reduce the number of statements?  
> **username_7** (2024-12-18): @xigoi, in K&R C, you have to declare on a separate line to assignment anyway, but you can also roll up multiple variable declarations (of the same type) in a comma-separated list, like: `int m, p, q, r;`. It was also common practice at the time to reuse declared variables (i.e. to assign them two or more times), rather than giving every unique value a separate variable, so combining declaration and assignment was seen as less useful back then than it is seen today.  
> **username_7** (2024-12-18): @xigoi, actually just clarifying a point in my previous comment, it wasn't that the initialiser syntax didn't exist in K&R, it was that all declarations had to be made at the beginning of the block before other statements, so it was impossible to use the initialiser syntax to assign a calculated value that was only produced midway through the block.  
> **username_3** (2024-12-22): @Steve: I think early compilers required that a compiler know how much space to allocate for a stack frame via "subtract" instruction which precedes any other executable code.  Initialization syntax which only works with constants could easily allow a compiler to use a "block move" to perform intiializations.  
---
### Answer by username_9 on 2024-12-30. Score: 0
Leaving aside the design problems with the choice of operator punctuation, there are a few reasons I'd like to have such an operator (or, as supercat correctly notes, a family of sequencing operators.)
First, many languages make a syntactic distinction between expressions and statements. C# for example has many contexts in which statements are not allowed but expressions are, and if the only way you have to represent "evaluate this expression for its side effects then evaluate this expression for its value" is to create two statements, then you cannot express that logic using the (often more elegant) expression context. Suppose we had an operator SEQ; which is nicer?
int UpdatedCount { DownloadLatestData(); return this.count; }
int UpdatedCount => DownloadLatestData() SEQ this.count;

It's a small difference in this example but these small differences add up.
Second, the C# compiler internally does have sequencing operators; they are very helpful as intermediate lowerings en route to generating code. Similar to goto -- what is good for the compiler team is likely also useful for the user.
And more generally, it's more pleasant to write a spec for a language when you can say precisely what a high-level feature desugars to in terms of lower-level language features, rather than describing the semantics of an operator that is in the compiler implementation but not in the language being compiled.
---
