From: Yong Li Date: 2011-12-30T16:41:25+09:00 Subject: Re: Hash access Hi Josh, Here is how Hash in Ruby works when it tries to determine if two keys are equal: * the #hash method on both objects are called to calculate their hash codes * if their hash codes are not equal, they are not equal * if their hash codes are equal, then #== is called to determine if two objects are equal In your example, all three objects actually return the same hash codes, so #== (instead of eql?) is used to check their equality. The "first Josh" and the "second Josh" are equal because their #== (inherited from Object#==) simply calls #eql? which you have overridden to make them equal. The "first Josh" is not equal to "Josh" because they are of different classes, and User#== (inherited from Object#==) does not allow objects of different classes to be equal. As a side note: you should always define #hash and #== together and make sure whenever #== returns true #hash mush return the same number, otherwise, using these objects as hash keys will break the hash semantics. Also, avoid using mutable objects as hash keys unless their #hash number is immutable. I hope this helps On Fri, Dec 30, 2011 at 1:37 PM, Josh Cheek wrote: > Hi, was playing around with an idea after reading the thread about defining > #hash. My understanding was that #hash gives a unique identifier, and that > #eql? allows the hash to determine whether the two objects are equal in > terms of being the same hash key. So I wrote some code that should take an > equivalent instance, or a string for quick access. But it behaves in a way > that I completely don't understand. Hoping someone can help: > > > User = Struct.new :name, :age, :identifier do >  def hash >    name.hash >  end > >  def eql?(other) >    puts "#{name} was asked if they were equal to #{other.inspect}" >    (other == name) || (other.name == name && other.age == age) >  end > end > > josh = User.new 'Josh', 28, 'first Josh' > hash = {josh => josh} > > hash[josh]                                # => # age=28, identifier="first Josh"> > hash[User.new 'Josh', 28, 'second Josh']  # => # age=28, identifier="first Josh"> > hash['Josh']                              # => nil > > # >> Josh was asked if they were equal to # age=28, identifier="first Josh"> > > > > So I would have expected all three to go through eql? Instead, we see that > only the case where the key was the same object goes through. However, it > identifies that the second Josh is the same key, without invoking User#eql? > How does it do this? > > And why does the string "Josh" not find the instance? > > This is all probably in my copy of the Pickaxe, but it's in Chicago and I'm > out of town :/