45

I can understand why the assignment operator is right associative. It makes sense that when

x = 4 + 3

is evaluated, that 4 and 3 are added before being assigned to x.

I am unclear as to how ?: would benefit from being right associative. Does it only matter when two ?:s were used like this

z = (a == b ? a : b ? c : d);

Then it is evaluated like this:

z = (a == b ? a : (b ? c : d));

Surely it would make more sense to evaluate from left to right?

Kindred
  • 1,229
  • 14
  • 41
Angus Comber
  • 9,316
  • 14
  • 59
  • 107
  • 1
    In `x = 4 + 3`, the only restriction on order of evaluation is that the operands of any operator must be evaluated before the operator itself is applied. Neither `=` nor `+` imposes any ordering on the evaluation of its operands. For `x = 4 + 3`, the left operand `x` and the right operand `4 + 3` must both be evaluated before the assignment takes place, but that can happen in either order. Note that evaluating the left operand `x` refers to determining the object to be assigned to. In a more complex example, `arr[func1()] = func2();`, the two functions can be called in either order. – Keith Thompson Sep 13 '11 at 19:43
  • 1
    Yes, I think I was unclear/incorrect there. Being right associative means you can do x = y = 4; and 4 will be correctly assigned to both y and x – Angus Comber Sep 13 '11 at 19:53
  • 2
    Just for completeness: If assignment was left associative `x = y = 4` would fail. First, y would be assigned to x and "return" an rvalue with the value of y. This rvalue would then be assigned to 4 which is illegal. – Oscar Korz Sep 13 '11 at 20:08
  • 4
    php is left associative, and causes all sorts of issues. http://www.phpsadness.com/sad/30 – Cameron MacFarland Nov 21 '12 at 07:26

3 Answers3

51

If it evaluated from left to right, it'd look like this:

z = ((a == b ? a : b) ? c : d);

That is, it would use the result of the first conditional (a or b) as the boolean condition of the second conditional. That doesn't make much sense: that's like saying:

int z, tmp;
/* first conditional */
if(a == b) tmp = a;
else       tmp = b;
/* second conditional */
if(tmp) z = c;
else    z = d;

While perhaps one day you'll want to do exactly this, it's far more likely that each ?: that follows is meant to add more conditions, like if / else if / else if / else, which is what the right-associative binding yields:

int z;
/* first conditional */
if(a == b)                          z = a;
else /* second conditional */ if(b) z = c;
else                                z = d;
Chris Lutz
  • 73,191
  • 16
  • 130
  • 183
28

In any language with a right associative ternary operator, you can stack them and build an if-elseif-elseif-else expression, like this:

val = a == 0 ? 1:
      a == 1 ? 2:
               4;

On the contrary, in languages with a left associative ternary operator (such as PHP, thanks @user786653) you need to explicitly enforce the aforementioned intent with parentheses:

<?php
// This will output 't', not 'true'.
echo (true ? 'true' : false ? 't' : 'f');

// the following is a more obvious version of the same code as above
echo ((true ? 'true' : false) ? 't' : 'f');

// here, you can see that the first expression is evaluated to 'true', which
// in turn evaluates to (bool)true, thus returning the true branch of the
// second ternary expression.
?>
Michael Foukarakis
  • 39,737
  • 6
  • 87
  • 123
  • 14
    Off-topic, but I can't resist linking to the [PHP manual](http://www.php.net/manual/en/language.operators.comparison.php#language.operators.comparison.ternary) for an example of *left* associative ternary operator. – user786653 Sep 13 '11 at 19:31
  • 9
    I'd say it's perfectly on-topic. The question was *why* the conditional operator is right-associative (though the OP may not have quite understood what that means). The PHP example shows the drawbacks of defining the conditional operator to be left-associative. – Keith Thompson Sep 13 '11 at 19:58
  • I tied to edit your answer to fix the typo, "will output 't" should be "will output 'f'". My edit was held for peer review. – Shelby Moore III Oct 06 '12 at 15:39
  • 1
    Why do you think there's a typo? Run the example. – Michael Foukarakis Oct 07 '12 at 02:21
  • 1
    Can also do a `nested if` too; like for eg : `a > b ? a > c : a : c : b > c ? b : c;` is like `(a > b ? (a > c : a : c) : (b > c ? b : c));` – Zaid Khan Mar 08 '17 at 10:42
  • Thanks @Bateman, I will use that as my go-to example of unreadable code. – Michael Foukarakis Mar 08 '17 at 10:45
6

You got the concept of associativity wrong.

When operator + is said to be left-associative, this means that a + b + c is equivalent to (a + b) + c, as opposed to a + (b + c).

The operator = is right-associative, which means that a = b = c is equivalent to a = (b = c), as opposed to (a = b) = c.

Associativity has nothing to do with the order of evaluation.

Roland Illig
  • 40,703
  • 10
  • 88
  • 121
  • 5
    "Associativity has nothing to do with the order of evaluation." Well, unless all the operators have the same precedence. – Chris Lutz Sep 13 '11 at 19:34
  • 4
    I was referring to *4 and 3 are added before being assigned to x*. Whether the right hand side or the left hand side of the operator is evaluated first, has nothing to do with the associativity. And no matter if the operator is right associative or left associative, the operands must always be evaluated *before* doing the actual operation. – Roland Illig Sep 13 '11 at 19:39
  • 1
    You're correct about the addition/assignment thing, and it's good to clarify that bit, but that's not really what the OP's after, and his statement can easily be amended to "I understand why `x = 4 - 2 - 1` returns 1 instead of 3." Nothing you've said so far has anything to do with his question on why `?:` is right associative. – Chris Lutz Sep 13 '11 at 19:41
  • 1
    @Chris: How so? In `a + b + c`, associativity specifies which operands are associated with which operators, but `a`, `b`, and `c` can be evaluated in any of 6 possible orders. This doesn't make much difference for evaluating a variable, but consider `func1() + func2() + func3()`; the functions can be called in any order. – Keith Thompson Sep 13 '11 at 19:45
  • 1
    @Keith - I know that, but I don't see how any of it is relevant to "why is `?:` right-associative instead of left-associative." – Chris Lutz Sep 13 '11 at 19:49
  • 1
    @Chris: It isn't -- which is why I posted it as a comment, not as an answer. It's relevant to your comment, "... Well, unless all the operators have the same precedence." – Keith Thompson Sep 13 '11 at 19:52
  • @Chris: did you see the question *Does it only matter when two ? s were used*? I think that is a very clear sign that the OP needs some clarification here. – Roland Illig Sep 13 '11 at 19:53
  • 2
    @Keith - My brain is somewhere else. I still don't undetstand why this answer starts discussing order of evaluation, but when I read that I was clearly not thinking about what "order of evaluation" actually was. – Chris Lutz Sep 13 '11 at 19:55
  • 1
    @Roland - But saying "in `a + b + c`, `a`, `b` and `c` can be evaluated in any order" isn't relevant to `?:` because there's a sequence point between the first operand and the second or third operand. They get evaluated in "the order you'd expect them to." – Chris Lutz Sep 13 '11 at 20:00
  • @ChrisLutz I believe you used "order of evaluation" in a slightly different way than others to mean evaluation of the expression as a whole to determine the final answer. What others mean by "order of evaluation" is the order in which individual components of the expression are evaluated at runtime (afer associativity has been determined). – Ankur Agarwal Jun 29 '14 at 20:52
  • @ChrisLutz Associativity determines the final answer, order of evaluation of individual components at runtime is non-deterministic. However once they are determined, they are plugged in and associativity determines the "order of evaluation" of the expression as a whole to get the final answer. – Ankur Agarwal Jun 29 '14 at 20:52
  • @RolandIllig It's actually incorrect to say that "in `a = b + c`, `b + c` has to be evaluated first". At the machine level, there are two operands to evaluate: the value to move, and the address to move that value to. `a`, which provides the address to put the sum in, can be calculated before or after the sum. If we replace `a` with a deferenced pointer, and add a side effect that modifies where that pointer points to the right hand side, the order of evaluation can affect the result. Some languages specify the order of evaluation; in C, it's probably undefined behavior. – Theodore Murdock Aug 29 '19 at 18:15
  • @Theodore you're right, and that's exactly why I never said that. And by the way, `a = b + c` is not undefined behavior in C (as that would make the language unusable). It's only that _the order of evaluation is unspecified_. There's a big difference between unspecified and undefined. – Roland Illig Aug 29 '19 at 21:54
  • Sorry, rereading your comment, I see you were getting at roughly the same point I was in mine, pointing out that it's the associativity that creates the difference in evaluation order between addition and assignment...sorry for being a bit slow to recognize that. Thanks for the reminder on unspecified vs. undefined. – Theodore Murdock Sep 04 '19 at 01:14