Comparison of equality operators in Ruby: == vs. equal? vs. eql? vs. ===


Here is a short explanation of when these predicates are true (From http://www.wellho.net/mouth/985_Equality-in-Ruby-eql-and-equal-.html)

The == comparison checks whether two values are equal
eql?
checks if two values are equal and of the same type
equal?
checks if two things are one and the same object.

How do I remember which is which ... The longer the operator, the more restrictive the test it performs
Let's understand the differences with some examples.

Each "abc" below is a different object. Therefore, equal? is false.

irb(main):065:0> "abc".object_id
=> 24173330
irb(main):066:0> "abc".object_id
=> 24165760
irb(main):067:0> "abc" == "abc"
=> true
irb(main):068:0> "abc".eql? "abc"
=> true
irb(main):069:0> "abc".equal? "abc"
=> false

As you might expect, there is a single instance of 1. Therefore, all comparisons are true.

irb(main):094:0> 1.class
=> Fixnum
irb(main):095:0> 1.object_id
=> 3
irb(main):096:0> 1.object_id
=> 3
irb(main):097:0> 1 == 1
=> true
irb(main):098:0> 1.eql? 1
=> true
irb(main):099:0> 1.equal? 1
=> true

Interestingly, contrary to the previous case, 1.0.object_id returns a different id each time so it is a different object each time. Therefore, equal? is false.

irb(main):100:0> 1.0.class
=> Float
irb(main):101:0> 1.0.object_id
=> 41452790
irb(main):102:0> 1.0.object_id
=> 41439520
irb(main):103:0> 1.0 == 1.0
=> true
irb(main):104:0> 1.0.eql? 1.0
=> true
irb(main):105:0> 1.0.equal? 1.0
=> false


Since 1 and 1.0 are of different types, eql? is false, and since 1 and 1.0 are different objects equal? is false.

irb(main):106:0> 1 == 1.0
=> true
irb(main):107:0> 1.eql? 1.0 #
=> false
irb(main):108:0> 1.equal? 1.0
=> false


For two arrays with the same content, == and eql? return true.

irb(main):275:0> [1,2,3].object_id
=> 24319440
irb(main):276:0> [1,2,3].object_id
=> 24310220
irb(main):277:0> [1,2,3] == [1,2,3]
=> true
irb(main):278:0> [1,2,3].eql? [1,2,3]
=> true
irb(main):279:0> [1,2,3].equal? [1,2,3]
=> false

For two hashes with the same content, interestingly, eql? returns false.

irb(main):282:0> {1=>2,2=>3}.object_id
=> 24216270
irb(main):283:0> {1=>2,2=>3}.object_id
=> 24210160
irb(main):284:0> {1=>2,2=>3} == {1=>2, 2=>3}
=> true
...
irb(main):286:0> {1=>2,2=>3}.eql?({1=>2, 2=>3})
=> false
irb(main):287:0> {1=>2,2=>3}.equal?({1=>2, 2=>3})
=> false


Update:

Regarding the comment suggesting a discussion of === operator, I refer to the article here:

In summary, === operator is case operator meaning it is mostly used in case statements.
It can mean 3 different things depending on who calls this operator. To clarify things a bit, in a statement like x === y, we can say x is calling === method with the input y.

If a class (i.e., class object) calls === operator, this returns true if the input an instance of the class.
For instance,
String === "abc" returns true. Because "abc" is an instance of String class.

If a range object calls the operator, then this returns true if the input is in the range.
For instance,
(1..10) === 2.5 returns true while (1..10) === 11 returns false.

For the rest of the objects, it acts like == operator.
For instance,
1 === 1.0 returns true because 1 == 1.0 returns true.
Similarly, "abc" === "abc" returns true.



Comments

JNK said…
This is really interesting. How about adding === too? I thought it was the same as eql? but check this:

a=10
b=10.0
a===b # true
a.eql?(b) # false

Both === and eql? test for value equality and type, don't they? Why do they behave differently?

Popular posts from this blog

Accessing Resources in Java, use of getResource method of Class and ClassLoader, How to access test data in unit tests

The Order of Rails Validation Filters