Dale Martenson
4/28/2006 9:33:00 PM
You don't have to define #hash. It depends on the behavior you wish to
have. I like to think of it as:
#eql? and #== are used to check equivalence.
#equal? is used to check sameness as it relates to object space.
#hash is used to check sameness as it relates to Hash only.
That means that if you wish to treat equivalent objects as the same key
values for a Hash you must define #hash. Otherwise, they will be seen
as unique key values for the Hash.
Please correct me if I am wrong, but this is my understanding.
I think generating a 24-bit number is a fine idea. I even use that
method in my example below.
Here is a long boring example that attempts to illustrate some of the
differences:
class RGB1
attr_accessor :r, :g, :b
def initialize(r,g,b)
@r = r
@g = g
@b = b
end
end
class RGB2 < RGB1
def eql?(x)
((@r==x.r)&&(@g==x.g)&&(@b==x.b))
end
def ==(x)
((@r==x.r)&&(@g==x.g)&&(@b==x.b))
end
end
class RGB3 < RGB2
def hash
@r<<16|@g<<8|@b
end
end
def test_equivalence( class1, class2 )
puts "#{class1}.new(255,0,0).eql?(#{class2}.new(255,0,0)):
#{class1.new(255,0,0).eql?(class2.new(255,0,0))}"
puts "#{class1}.new(255,0,0) == #{class2}.new(255,0,0):
#{class1.new(255,0,0) == class2.new(255,0,0)}"
puts "#{class1}.new(255,0,0).equal?(#{class2}.new(255,0,0)):
#{class1.new(255,0,0).equal?(class2.new(255,0,0))}"
puts "-----------------------------------------------------------"
end
def test_hash( class1 )
puts "Using #{class1}:"
h = {}
h[class1.new(255,0,0)] = 10
h[class1.new(255,0,0)] = 20
h.each_pair {|k,v| puts "h[#{k}]: #{v}"}
puts "-----------------------------------------------------------"
end
test_equivalence( RGB1, RGB2 )
test_equivalence( RGB1, RGB1 )
test_equivalence( RGB2, RGB2 )
test_equivalence( RGB3, RGB3 )
test_hash(RGB2)
test_hash(RGB3)
++++++++++++++++ END OF CODE ++++++++++++++++
The output from the above would be:
RGB1.new(255,0,0).eql?(RGB2.new(255,0,0)): false
RGB1.new(255,0,0) == RGB2.new(255,0,0): false
RGB1.new(255,0,0).equal?(RGB2.new(255,0,0)): false
-----------------------------------------------------------
RGB1.new(255,0,0).eql?(RGB1.new(255,0,0)): false
RGB1.new(255,0,0) == RGB1.new(255,0,0): false
RGB1.new(255,0,0).equal?(RGB1.new(255,0,0)): false
-----------------------------------------------------------
RGB2.new(255,0,0).eql?(RGB2.new(255,0,0)): true
RGB2.new(255,0,0) == RGB2.new(255,0,0): true
RGB2.new(255,0,0).equal?(RGB2.new(255,0,0)): false
-----------------------------------------------------------
RGB3.new(255,0,0).eql?(RGB3.new(255,0,0)): true
RGB3.new(255,0,0) == RGB3.new(255,0,0): true
RGB3.new(255,0,0).equal?(RGB3.new(255,0,0)): false
-----------------------------------------------------------
Using RGB2:
h[#<RGB2:0x27db1e8>]: 10
h[#<RGB2:0x27d8d58>]: 20
-----------------------------------------------------------
Using RGB3:
h[#<RGB3:0x27d5248>]: 20
-----------------------------------------------------------