Samuel Tesla wrote:
Ferenc Engard ferenc@engard.hu writes:
What does hash comparison mean? I have read the Object#hash and
Object#eql? documentation, but they do not mention arrays. Moreover,
there comes the question: what the default Object#hash do? It has a
generic algorithm which computes something based on the object’s
attributes?
Hash comparison means that it compares the value of Object#hash for each
object. This is where a quick look at the Ruby source is very enlightening.
Having had to do some battle with these methods recently myself, I have the
code fresh in my mind. Object#hash just returns the object ID by default.
This is done in C code, so if you override Object#object_id, it will not return
what you expect.
Sorry, I didn’t look in the source, yet, but I have made some
experiments with this simple program:
class A
attr_accessor :x
def eql?(o) @x==o.x end
def hash
15
end
end
a=A.new
b=A.new
c=A.new
d=A.new
a.x=1
b.x=2
c.x=2
d.x=3
ar1=[a,b]
ar2=[b]
ar3=[c]
ar4=[d]
ar5=[d,d]
ar6=[b,c]
puts “b.eql?(c)==true”
puts “[a,b]==”+(ar1).inspect
puts “[a,b].uniq==”+(ar1.uniq).inspect
puts “[a,b]-[b]==”+(ar1-ar2).inspect
puts “[a,b]-[c]==”+(ar1-ar3).inspect
puts “[a,b]-[d]==”+(ar1-ar4).inspect
puts “[d,d].uniq==”+(ar5.uniq).inspect
puts “[b,c].uniq==”+(ar6.uniq).inspect
···
The output is:
b.eql?(c)==true
[a,b]==[#<A:0x402d90ac @x=1>, #<A:0x402d8fe4 @x=2>]
[a,b].uniq==[#<A:0x402d90ac @x=1>, #<A:0x402d8fe4 @x=2>]
[a,b]-[b]==[#<A:0x402d90ac @x=1>]
[a,b]-[c]==[#<A:0x402d90ac @x=1>]
[a,b]-[d]==[#<A:0x402d90ac @x=1>, #<A:0x402d8fe4 @x=2>]
[d,d].uniq==[#<A:0x402d8fbc @x=3>]
[b,c].uniq==[#<A:0x402d8fe4 @x=2>]
Which seems correct. Now if I comment out the hash method, the output
changes:
b.eql?(c)==true
[a,b]==[#<A:0x402d9174 @x=1>, #<A:0x402d90d4 @x=2>]
[a,b].uniq==[#<A:0x402d9174 @x=1>, #<A:0x402d90d4 @x=2>]
[a,b]-[b]==[#<A:0x402d9174 @x=1>]
[a,b]-[c]==[#<A:0x402d9174 @x=1>, #<A:0x402d90d4 @x=2>]
[a,b]-[d]==[#<A:0x402d9174 @x=1>, #<A:0x402d90d4 @x=2>]
[d,d].uniq==[#<A:0x402d90ac @x=3>]
[b,c].uniq==[#<A:0x402d90d4 @x=2>, #<A:0x402d90c0 @x=2>]
I.e. b and c are no longer considered equal. Based on that, I have made
the following conclusion:
- The array object first gets the hash of the objects it contains
- If two object’s hashes are not equal, then it considers as different
objects
- If the hash values are equal, then if first.eql?(second) is true,
then it considers the objects as equal, otherwise not.
Just like a hash index in a database. So, if I am lazy, can I implement
the #hash method like this, and it will only result in a bigger
comparison executing time because of the more #eql? comparisons, but
will work correctly?
Thanks for the help:
Ferenc