Why does the expression (true == true == true) produce a syntax error?

RubySyntax ErrorOperatorsOperator PrecedenceAssociativity

Ruby Problem Overview


Ruby:

true == true == true

> syntax error, unexpected tEQ

vs. JavaScript:

true == true == true
// => true

vs. C:

1 == 1 == 1
// => 1

Ruby Solutions


Solution 1 - Ruby

Association direction, which controls the order of operators having their arguments evaluated, is not defined for the == method, same as for ===, !=, =~ and <=> methods as well (all of which have the same precedence and form a separate precedence group exclusively).

Documentation

Thus evaluation order in case of multiple operators from the list mentioned above being chained in a row should be set explicitly via either

  • parenthesis ():

     (true == true) == true # => true
     true == (true == true) # => true
    
  • or dot operator . (can be omitted for the last equality check in a row):

     true .== true == true # => true
    

Solution 2 - Ruby

TL;DR The syntax implies that all 3 values are equal this is not what it does in javascript or C, so by ruby giving a syntax error the door is open for this to be implemented in the future.

If I understand the question correctly value_a == value_b == value_c should only return true if they are all equal using == as the comparison operater as shown in this method

# version 1
def compare_3_values(a, b, c)
  a == b && a == c && b == c
end

there is another possible expected outcome though. to implement this as shown in the previous answer:

#version 2
def compare_3_values(a, b, c)
  (a == b) == c
end

The results are worlds apart.

JavaScript always uses version 2 which is pretty useless as the 3rd item is always being compared against true or false (0 or 1 if the 3rd item is an integer) that's why false == false == true returns true.

> The good news is that because ruby gives a syntax error it's the only language that can implement this without breaking everyone's code. > > for any other language it would break so much code that even if it were implemented in a later major version there would need to be a flag/setting to turn this on or off for years to come, hence it will never be worthwhile.

Some interesting results in Ruby

false .== false == true
=> true

false .== true == false
=> true

true .== false == false
=> true

false .== false == false
=> false

true .== true == false
false

And in javascript

false == false == true
=> true

false == true == false
=> true

true == false == false
=> true

false == false == false
=> false

true == true == false
=> false

Edit tested in C as well, acts similar to JavaScript in that it compares the result of the first two values against the third value

Solution 3 - Ruby

The first answer is excellent, but just in case it's not completely clear (and people asking why), here are few more examples.


In C, the == operator is left-to-right associative and boolean is represented as 1 (true) and 0 (false), so the first 1 == 1 evaluates to 1 (true) and then you are evaluating the result of first expression with the second. You can try:

2 == 2 == 2 // => 0

Which in C, is evaluated as:

(2 == 2) == 2
1 == 2 // => 0

In Javascript, similarly to C, == is left to right associative. Let's try with 0 this time (although the same example from C would work as well):

0 == 0 == 0
false
 

Again:

0 == 0 == 0
true == 0 // => false

In Ruby == does not have associative properties, ie. it can't be used multiple times in single expression, so that expression can't be evaluated. Why that decision was made is a question for the author of the language. Further, Ruby doesn't define numeric 1 as a boolean, so 1 == true evaluates to false.

The second answer states there are some "weird" cases in Ruby, but they all evaluate as expected:

(1 == 1) == 1
true == 1 # => false

1 == (1 == 1)
1 == true # => false

1 .== 1 == 1
(1 == 1) == 1
true == 1 # => false

false .== false == true
(false == false) == true
true == true # => true

false .== true == false
(false == true) == false
false == false # => true

true .== false == false
(true == false) == false
false == false # => true

false .== false == false
(false == false) == false
true == false # => false

true .== true == false
(true == true) == false
true == false # => false

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRrr RrrView Question on Stackoverflow
Solution 1 - RubypotashinView Answer on Stackoverflow
Solution 2 - RubyArye EidelmanView Answer on Stackoverflow
Solution 3 - RubyMayoView Answer on Stackoverflow