# Overriding eql? and hash

**URL:** <https://www.ruby-forum.com/t/overriding-eql-and-hash/166501>\
**Category:** Ruby\
**Created:** [April 26, 2009, 12:05pm UTC](https://www.ruby-forum.com/t/overriding-eql-and-hash/166501 "2009-04-26T12:05:57Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![cesardiaz](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/dfb087/32.png) [@cesardiaz](https://www.ruby-forum.com/u/cesardiaz)\
**Post date:** [April 26, 2009, 12:05pm UTC](https://www.ruby-forum.com/t/overriding-eql-and-hash/166501/1 "2009-04-26T12:05:57Z")

</div>

Hi,

I am working in an application and I need to store my own objects in  
some collections. I was using instances of Array to store that objects,  
but now, I need not to store duplicated instances. Searching the Web I  
found de class ‘Set’, which seems to do that. I also read that with this  
collection you have to override the eql? and hash methods in your  
classes objects to set a criteria to compare you objects.

I will try to explain better myself with an example:

I have the following class Track

class Track \< ActiveRecord::Base  
belongs\_to :album

def hash  
StringUtils.nice\_slug(self.name, “false”).hash

end

def eql?(other)  
equal = false  
if StringUtils.nice\_slug(self.name, “false”).downcase.eql?  
StringUtils.nice\_slug(other.name, “false”).downcase  
equal = true  
end  
equal  
end  
end

Now, I create two instances of Track and two of Set, and I insert one  
track into each Set.

a = Set::new

t1 = Track.new

=\> #\<Track id: nil, name: nil, lyric: nil, created\_at: nil, updated\_at:  
nil\>

t1.name = “Gracias por elegirme”

t2 = Track.new

=\> #\<Track id: nil, name: nil, lyric: nil, created\_at: nil, updated\_at:  
nil\>

t2.name = “Gracias Por Elegirme”

a \<\< t1

=\> #\<Set: {#\<Track id: nil, name: “Gracias por elegirme”, lyric: nil,  
created\_at: nil, updated\_at: nil\>}\>

b = Set::new

b \<\< t2

#\<Set: {#\<Track id: nil, name: “Gracias Por Elegirme”, lyric: nil,  
created\_at: nil, updated\_at: nil\>}\>

And finally, I try to insert the content of b into a:

a.merge(b)

The result that I am expecting is that nothing is inserted into a  
because the name of the two tracks is very similar, and when we convert  
into downcase the are equal (“gracias por elegirme”).

But instead I get the following:

#\<Set: {#\<Track id: nil, name: “Gracias Por Elegirme”, lyric: nil,  
created\_at: nil, updated\_at: nil\>, #\<Track id: nil, name: “Gracias por  
elegirme”, lyric: nil, created\_at: nil, updated\_at: nil\>}\>

Now a stores the two Track instances.

I would appreciate so much your help.

---

<div class="post-metadata">

**Author:** ![cesardiaz](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/dfb087/32.png) [@cesardiaz](https://www.ruby-forum.com/u/cesardiaz)\
**Post date:** [April 26, 2009, 1:40pm UTC](https://www.ruby-forum.com/t/overriding-eql-and-hash/166501/2 "2009-04-26T13:40:28Z")

</div>

CÃ©sar DÃ­az wrote:

> Â Â end  
> Â Â equal  
> Â end

If two strings are equal except for case your eql? method will return  
true. Or  
at least it would if it ever got called. But since you don’t call  
downcase in  
the hash method, those two objects will have different hash values and  
Set  
will never bother to call eql? on them.  
In other words: call downcase in the hash method as well and you’ll be  
fine.

HTH,  
Sebastian

---

<div class="post-metadata">

**Author:** ![cesardiaz](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/dfb087/32.png) [@cesardiaz](https://www.ruby-forum.com/u/cesardiaz)\
**Post date:** [April 26, 2009, 4:53pm UTC](https://www.ruby-forum.com/t/overriding-eql-and-hash/166501/3 "2009-04-26T16:53:52Z")

</div>

It works perfectly.

Thank you very much!!!
