Ruby Tip #1: Demystifying the Difference Between == and eql?

Newcomers to Ruby are often confused by the fact the Object class defines three methods related to equality - ==, eql? and equal?. Of the three the one that it’s easiest to describe is equal? - it implements what’s commonly known as reference equality check. The method returns true only if its receiver (the object upon the method was invoked) and parameter (the object we’re comparing to) are the same object (Java developers should think of the == operator there).

some_word = "word"
some_other_word = some_word

some_word.equal? some_other_word # true

Both == and eql? implement value equality checks - they are not interested in whether two variables point to the same object in memory, but whether two objects are equal in terms of their values. For instance “cat” and “cat” might very well be two completely different String objects, but they are quite obviously the same as far as their value is concerned.

"cat".equal? "cat"     # false
"cat" == "cat"         # true
"cat".eql? "cat"       # true

What’s not immediately obvious is why are there two different methods that seem to be doing exactly the same thing. The answer is simple - eql? is meant to be used as a stricter version of ==, if there is a need for such stricter version.eql? most prominent usage is probably in the Hash class, where it’s used to test members for equality.

In the Object class eql? is synonym with ==. Most subclasses continue this tradition, but there are a few classes that provide a different implementation for eql?. Numeric types, for example, perform type conversion across ==, but not across eql?, so:

1 == 1       # true
1.eql? 1     # true
1 == 1.0     # true
1.eql? 1.0   # false
1.0.eql? 1.0 # true

As you can see clearly from this example - eql? for Numeric classes requires both objects to be instances of the same class, apart from having equal values, to return true.

If you’re wondering about the origins of that convention I should probably refer you to Common Lisp (one of the languages cited as principle inspiration for Ruby). Common Lisp has quite a few equality predicates, dealing with various aspects of equality. I guess I never found == and eql? in Ruby particularly confusing, because I knew Common Lisp, before I started playing with Ruby.

Hopefully, I’ve managed to make the difference between == and eql? clear. That’s some fairly esoteric matter that’s not totally understood by even some fairly experienced Ruby developers.