I was posed a question recently as to why the C++ expression true == true == true compiled successfully. The person asking was sure that equality comparison held no associativity and that the expression was thus too ambiguous to be well-formed.

Well, in Ruby, this is the case:

  • Subtraction is left associative;
    so a - b - 3 acts like (a - b) - 3.

  • Assignment is right associative;
    so a = b = 3 acts like a = (b = 3).

  • Equality is not associative;
    so a == b == 3 raises SyntaxError.

In fact, C++'s equality operator is left associative, and my immediate thought was that Ruby's behaviour was a little odd.

However, on further thought, I realised that it makes quite a bit of sense.

For example, it essentially prevents the following mistake:

int x = 0, y = 0, z = 0;
std::cout << (x == y == z); // false

Naively, especially when coming directly from a mathematics background, one might expect the output of this program to be true because all three operands are equal.

But in fact, C++'s comparison takes only two operands, and when implicit associativity is applied explicitly with parentheses, the program's true behaviour becomes more obvious:

int x = 0, y = 0, z = 0;
std::cout << ((x == y) == z);
//              true   == 0
//                 false

Ruby's position of completely disallowing such a form in its arithmetic expressions will prevent any such "bugs". Perhaps it would have been better had C++ adopted this position as well.