Why does this comma inside a ternary operator throw a syntax error in JavaScript?
This is an intentional part of the language, and is outlined in the ECMAScript Language Specification. The syntax for the comma operator is defined in Section 12.16, which states the following:
12.16 Comma Operator ( , )
Syntax
Expression: AssignmentExpression Expression, AssignmentExpression
Here, the specification outlines how the comma operator is used. An Expression
is any AssignmentExpression
or itself followed with a comma (the operator) and another AssignmentExpression
. The important thing to note is that an AssignmentExpression
is an Expression
but an Expression
is not an AssignmentExpression
.
As for the actual conditional operator, the grammar for the operator and conditional expressions is specificed in Section 12.14:
12.14 Conditional Operator ( ? : )
Syntax
ConditionalExpression: LogicalORExpression LogicalORExpression ? AssignmentExpression : AssignmentExpression
By the specification, a conditional expression can only contain AssignmentExpression
s -- not just Expression
s. Thus a conditional operator cannot have a comma operator inside one of its operands. This may seem like a weird quirk of language, but there is a specific reason considering the very specific grammar, and per the specification:
NOTE The grammar for a
ConditionalExpression
in ECMAScript is slightly different from that in C and Java, which each allow the second subexpression to be anExpression
1 but restrict the third expression to be aConditionalExpression
. The motivation for this difference in ECMAScript is to allow an assignment expression to be governed by either arm of a conditional and to eliminate the confusing and fairly useless case of a comma expression as the centre expression.
Because of Java and C's restrictive grammar, they do not allow things like this (Java):
int a = 2;int b = 1;System.out.println(a > b ? b = a : a = b); //Can't use assignment in 'else' part// ^^^^^
ECMAScript authors decided to allow for assignment in both branches of the ternary operator, thus this definition with AssignmentExpression
occurred. Consequently, this definition also disallows for the comma operator to actually show up in the 'if' part of the conditional operator, but because of its scarcity and uselessness it wasn't a problem. They essentially killed two birds with one stone; allowed for more lenient grammar and got rid of useless syntax that's bad practice.
The reason why adding the grouping operator allows it to work is because the grouping operator production ( Expression )
is by definition also an AssignmentExpression
allowing it to be in the ternary operator, see str's answer for more details.
1 This refers to Java's Expression
, not ECMAScript's Expression
. Java's does not have the comma operator so its Expression
does not include it.
This answer is meant as an extension of Li357's answer. Specifically to show where in the grammar the Conditional Operator allows PrimaryExpression
s (which does not include the Comma Operator) but not Expression
s (which does include the Comma Operator).
Please see the links to the specification for every mentioned type of expression or operator on the bottom of this answer.
The specification of the Conditional Operator is defined as follows:
ConditionalExpression: LogicalORExpression LogicalORExpression ? AssignmentExpression : AssignmentExpression
Thus it can be either a LogicalORExpression
only, or a combination of LogicalORExpression
and two AssignmentExpression
s. An AssignmentExpression
itself can, among other things, be specified by a LogicalORExpression
as well.
But unlike its simple sounding name, the LogicalORExpression
is not just a basic condition but can consist of many, many different nested expressions itself.All the way down to PrimaryExpression
which also includes grouped expressions (Expression)
.
And as can be seen in the specification of the Comma Operator, it is only specified in Expression
, but not in PrimaryExpression
itself.
Expression: AssignmentExpression Expression , AssignmentExpression
To summarize it in simpler words: The grammar of JavaScript only allows the comma operator within an AssignmentExpression
if it is contained within a grouping operator ()
.
Also see the Operator Precedence in JavaScript.