Hash#eql? and Hash key testing

The ri docs for Object#eql? say:

      The +eql?+ method returns +true+ if _obj_ and _anObject_ have the
      same value. Used by +Hash+ to test members for equality.

However, the second sentence doesn't seem to be consistent with the behavior of Hash (and Set):

   h1 = {1=>2, 3=>4}
   h2 = {1=>2, 3=>4}

   p h1.eql?(h2) # ==> true

   h={h1=>true}

   p h[h1] # ==> true
   p h[h2] # ==> nil

Based on the docs, I would have expected

   p h[h2] # ==> true

Have I misunderstood?

h1 and h2 are not the same object above, though they are equivalent at
the time you test for equality. h1 could get new elements, as could h2.

mcl@saluki:~$ irb
irb(main):001:0> a = {1=>2,3=>4}
=> {1=>2, 3=>4}

irb(main):002:0> b = {1=>2,3=>4}
=> {1=>2, 3=>4}

irb(main):003:0> a == b
=> true

irb(main):004:0> a.__id__ == b.__id__
=> false

irb(main):005:0> c = {a=>true}
=> {{1=>2, 3=>4}=>true}

irb(main):006:0> c[b] = 'foo'
=> "foo"

irb(main):007:0> c
=> {{1=>2, 3=>4}=>"foo", {1=>2, 3=>4}=>true}

irb(main):008:0> a[5]=6
=> 6

irb(main):009:0> c
=> {{1=>2, 3=>4}=>"foo", {5=>6, 1=>2, 3=>4}=>true}

irb(main):010:0> a == b
=> false

With literals it's a different story:

irb(main):011:0> x = 5
=> 5

irb(main):012:0> y = 5
=> 5

irb(main):013:0> x == y
=> true

irb(main):015:0> c = 'bar'
=> "bar"

irb(main):016:0> c
=> {5=>"bar", {1=>2, 3=>4}=>"foo", {5=>6, 1=>2, 3=>4}=>true}

irb(main):017:0> c[y]
=> "bar"

irb(main):018:0> x.__id__ == y.__id__
=> true

-Michael C. Libby, www.andsoforth.com

···

On Sat, 2004-12-04 at 16:39 +0900, Joel VanderWerf wrote:

The ri docs for Object#eql? say:

      The +eql?+ method returns +true+ if _obj_ and _anObject_ have the
      same value. Used by +Hash+ to test members for equality.

However, the second sentence doesn't seem to be consistent with the
behavior of Hash (and Set):

   h1 = {1=>2, 3=>4}
   h2 = {1=>2, 3=>4}

   p h1.eql?(h2) # ==> true

   h={h1=>true}

   p h[h1] # ==> true
   p h[h2] # ==> nil

Based on the docs, I would have expected

   p h[h2] # ==> true

Have I misunderstood?

Joel VanderWerf schrieb:

The ri docs for Object#eql? say:

     The +eql?+ method returns +true+ if _obj_ and _anObject_ have the
     same value. Used by +Hash+ to test members for equality.

However, the second sentence doesn't seem to be consistent with the behavior of Hash (and Set):

  h1 = {1=>2, 3=>4}
  h2 = {1=>2, 3=>4}

  p h1.eql?(h2) # ==> true

  h={h1=>true}

  p h[h1] # ==> true
  p h[h2] # ==> nil

Based on the docs, I would have expected

  p h[h2] # ==> true

Have I misunderstood?

No you have not, however hashes have different
Hash values (their ids - the same is true for Sets)
so all bets are off

···

----
class A
  def ==(rhs)
    true
  end
   alias :eql? :==
end

def test
  a,b = A.new,A.new
  ah = {a => true }
  bh = {b => true }
  p ah[b]
end

test # nil
class A
   def hash
    1
   end
end

test # true

class A
  remove_method :eql?
end

test # nil
---

/Christoph

Hi,

···

In message "Re: Hash#eql? and Hash key testing" on Sat, 4 Dec 2004 16:39:30 +0900, Joel VanderWerf <vjoel@PATH.Berkeley.EDU> writes:

The ri docs for Object#eql? say:

     The +eql?+ method returns +true+ if _obj_ and _anObject_ have the
     same value. Used by +Hash+ to test members for equality.

However, the second sentence doesn't seem to be consistent with the
behavior of Hash (and Set):

You are right. "hash" should be redefined as well.

              matz.

Christoph schrieb:

however hashes have different
Hash values (their ids - the same is true for Sets)

Correction: If I remember correctly Set uses something

def hash
    @rep_hash.hash
end

which is effectively the same as using the id of
the Sets as Hash values (which makes you wonder
why go through the trouble and provide the Set class
with a customized #hash method at all )

/Christoph