65

Ruby:

true == true == true

syntax error, unexpected tEQ

vs. JavaScript:

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

vs. C:

1 == 1 == 1
// => 1
potashin
  • 44,205
  • 11
  • 83
  • 107
Rrr Rrr
  • 603
  • 5
  • 6
  • 2
    The interesting thing is that it seems to only be the equality operators (`==`, `===`, and `!=`) that do this. Even `<` and `>` parse correctly and then produce a runtime error like you would expect. Plus, the [only](https://www.cse.buffalo.edu/~regan/cse305/RubyBNF.pdf) [sources](http://docs.huihoo.com/ruby/ruby-man-1.4/yacc.html) I can find which claim to have a complete grammar for Ruby would seem to indicate that this syntax is allowable. – Silvio Mayolo Jan 09 '18 at 00:18
  • 2
    it also works without parenthesis like this, with explicit calling, `true .== true .== true` – potashin Jan 09 '18 at 00:20
  • 4
    I wonder how many other people incredulously typed the failing code into irb expecting a different result? – Brad Werth Jan 09 '18 at 00:21
  • https://stackoverflow.com/a/21060235/2864740 - `==` is listed as **not-associative (A=N)** in the answer, meaning such a `X==Y==Z` production is invalid (associativity is what "adds the implicit parenthesis around operators of the same precedence"). There are many links in the question that might go back to a more "Official Source" that could be cleanly cited. (This question is more of less about a specific subset/application of grammar rules in that question/answer.) – user2864740 Jan 09 '18 at 00:23
  • @SilvioMayolo Per the answer above, `<` and friends *are* left-associative.. so should parse (and "work", given valid runtime inputs). I'm not sure what the grammar rational about why `<` would be associative while `==` would not be, although changing that might break lots of expectations.. – user2864740 Jan 09 '18 at 00:29
  • So we know that it's intended behavior, as per the provided link. Then it just comes down to why. I can't see a reason to make `==` non-associative but still let `<` and company have associativity. – Silvio Mayolo Jan 09 '18 at 00:31
  • @SilvioMayolo The "why" of grammar is often off-topic :) Although, a practical syntax example that works although it would not if there was associativity (ie. non-associativity allows this *other* construct form [by removing other ambiguity]) would be interesting to see. – user2864740 Jan 09 '18 at 00:34

3 Answers3

49

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
    
potashin
  • 44,205
  • 11
  • 83
  • 107
  • 1
    I would be interested in knowing *why*, but I think that's beyond the scope of the question and your answer. – Cary Swoveland Jan 09 '18 at 04:44
  • 13
    @CarySwoveland maybe because `1 == 1 == 1` would evaluate to `false` in Ruby if `==` was left-associative, which would probably result in several bugs. And it wouldn't make much sense either – the only reasonable values for the 3rd operand are `true` and `false`, i.e. `a == b == true` and `a == b == false` which can be expressed as `a == b` and `a != b`. – Stefan Jan 09 '18 at 08:22
  • 2
    @Stefan: there is only one situation when it can be used like this in a way that it would make sense, though I must say that the example is kinda far-fetched: `==` can be overriden in a custom class and thus equality check can return something other than just `true` or `false` (for example, `nil`) – potashin Jan 09 '18 at 17:34
  • 3
    @CarySwoveland I think it can be resolved from the language designer's point of view like [this](https://gist.github.com/anonymous/9593113c3a4323692676d44f5adaa9c9) – Rrr Rrr Jan 12 '18 at 01:57
  • [javascript-truthiness-in-boolean-to-numbers-comparison](https://stackoverflow.com/questions/6640637) why we should all stop using 0's or 1's in javascript examples comparing integers with integers or booleans – Arye Eidelman Apr 18 '18 at 21:37
7

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

Community
  • 1
  • 1
Arye Eidelman
  • 1,579
  • 16
  • 22
4

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
Mayo
  • 113
  • 1
  • 6