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 <josh.cheek / gmail.com> 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
>   
>  
>  
>
>  >       > other == name) || (other.name == name && other.age ==ge)
>  
> end
>
> josh = User.new 'Josh', 28, 'first Josh'
> hash = {josh => josh}
>
> hash[josh]  => #<struct User name="Josh",
> age=28, identifier="first Josh">
> hash[User.new 'Josh', 28, 'second Josh']  => #<struct User name="Josh",
> age=28, identifier="first Josh">
> hash['Josh'] 3D> nil
>
> # >> Josh was asked if they were equal to #<struct User name="Josh",
> 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 :/