# How does Array#- do comparisons?

**URL:** <https://www.ruby-forum.com/t/how-does-array-do-comparisons/133382>\
**Category:** Ruby\
**Created:** [March 31, 2008, 4:38am UTC](https://www.ruby-forum.com/t/how-does-array-do-comparisons/133382 "2008-03-31T04:38:01Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![adambeazley](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/5f9b8f/32.png) [@adambeazley](https://www.ruby-forum.com/u/adambeazley)\
**Post date:** [March 31, 2008, 4:38am UTC](https://www.ruby-forum.com/t/how-does-array-do-comparisons/133382/1 "2008-03-31T04:38:01Z")

</div>

How does Array#- (as in, [1, 2, 3, 1, 1] - [1]) compare two objects to  
see if they are equal? I would think the .eql? method, but I’ve  
written a class that implements that method so that two different  
objects with the same values are considered equal and ‘-’ isn’t  
functioning as I would expect. A contrived example:

irb(main):004:0\> class Hash  
irb(main):005:1\> def eql?(h)  
irb(main):006:2\> true  
irb(main):007:2\> end  
irb(main):008:1\> end  
=\> nil  
irb(main):010:0\> h1 = {‘a’ =\> 1}  
=\> {“a”=\>1}  
irb(main):011:0\> h2 = {‘a’ =\> 1}  
=\> {“a”=\>1}  
irb(main):012:0\> h1 == h2  
=\> true  
irb(main):013:0\> h1.eql? h2  
=\> true  
irb(main):014:0\> [h1] - [h2]  
=\> [{“a”=\>1}]

I would expect [] as a result, just like the following:  
irb(main):015:0\> [“asdf”] - [“asdf”]  
=\> []

Thanks,

Adam

---

<div class="post-metadata">

**Author:** ![adambeazley](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/5f9b8f/32.png) [@adambeazley](https://www.ruby-forum.com/u/adambeazley)\
**Post date:** [March 31, 2008, 8:59am UTC](https://www.ruby-forum.com/t/how-does-array-do-comparisons/133382/2 "2008-03-31T08:59:01Z")

</div>

On Monday 31 March 2008, Adam B. wrote:

> irb(main):008:1\> end  
> =\> [{“a”=\>1}]
> 
> I would expect [] as a result, just like the following:  
> irb(main):015:0\> [“asdf”] - [“asdf”]  
> =\> []
> 
> Thanks,
> 
> Adam

It uses eql?. However, before calling it, it calls the hash method of  
the two  
objects. If they return different values, they’re considered different  
and  
eql? is not called. If the two calls to hash return the same values,  
then eql?  
is called. The reason is that two objects which are eql? should also  
have the  
same hash value (see the ri documentation for Object#hash) and the  
comparison  
of hash values is tried first because (I think) of efficiency.

This make me think one should always follow this rule:  
“When you reimplement the eql? method, you should also reimplement the  
hash  
method (or at least, make sure the hash method returns the same value  
for  
objects which are eql?)”

This is an example:

class C

attr\_reader :x  
def initialize x  
@x = x  
end

def hash  
@x.to\_i  
end

def eql? other  
self.class == other.class and @x.eql? other.x  
end

end

a = [C.new(1), C.new(2)]  
p (a - [C.new(1)])

In this case, two objects of class C are eql? if their instance  
variables @x  
have the same value. Since hash returns @x (converted to an int), two  
objects  
which are eql? have hash methods which return the same value.

I hope this helps

Stefano

---

<div class="post-metadata">

**Author:** ![adambeazley](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/5f9b8f/32.png) [@adambeazley](https://www.ruby-forum.com/u/adambeazley)\
**Post date:** [March 31, 2008, 11:26am UTC](https://www.ruby-forum.com/t/how-does-array-do-comparisons/133382/3 "2008-03-31T11:26:27Z")

</div>

2008/3/31, Adam B. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> irb(main):008:1\> end  
> =\> [{“a”=\>1}]
> 
> I would expect [] as a result, just like the following:  
> irb(main):015:0\> [“asdf”] - [“asdf”]  
> =\> []

Another illustration of Stefano’s point:

irb(main):001:0\> class Foo; end  
=\> nil  
irb(main):002:0\> [Foo.new] - [Foo.new]  
=\> [#Foo:0x7ff994b0]  
irb(main):003:0\> class Foo  
irb(main):004:1\> def eql?(o) true end  
irb(main):005:1\> end  
=\> nil  
irb(main):006:0\> [Foo.new] - [Foo.new]  
=\> [#Foo:0x7ff80988]  
irb(main):007:0\> class Foo  
irb(main):008:1\> def hash;0 end  
irb(main):009:1\> end  
=\> nil  
irb(main):010:0\> [Foo.new] - [Foo.new]  
=\> []

Kind regards

robert
