Why does the expression (true == true == true) produce a syntax error?
RubySyntax ErrorOperatorsOperator PrecedenceAssociativityRuby 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).
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