Hash#eql? and Hash key testing

  • Thread starter Joel VanderWerf
  • Start date
J

Joel VanderWerf

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?
 
M

Michael C. Libby

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 = '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[x] = '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
 
C

Christoph

Joel said:
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
end

test # nil
class A
def hash
1
end
end

test # true

class A
remove_method :eql?
end


test # nil
 
Y

Yukihiro Matsumoto

Hi,

In message "Re: 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):

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

matz.
 
C

Christoph

Christoph said:
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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,902
Latest member
Elena68X5

Latest Threads

Top