tags:

views:

295

answers:

2

I have a class Foo with a few member variables. When all values in two instances of the class are equal I want the objects to be 'equal'. I'd then like these objects to be keys in my hash. When I currently try this, the hash treats each instance as unequal.

h = {}
f1 = Foo.new(a,b)
f2 = Foo.new(a,b)

f1 and f2 should be equal at this point.

h[f1] = 7
h[f2] = 8
puts h[f1]

should print 8

+16  A: 

See http://ruby-doc.org/core/classes/Hash.html

Hash uses key.eql? to test keys for equality. If you need to use instances of your own classes as keys in a Hash, it is recommended that you define both the eql? and hash methods. The hash method must have the property that a.eql?(b) implies a.hash == b.hash.

The eql? method is easy to implement: return true if all member variables are the same. For the hash method, use [@data1, @data2].hash as Marc-Andre suggests in the comments.

Mark
Perfect explanation. =)
Mereghost
Good, except that returned hash should be a fixnum, so better use exclusive or instead of sum (which could overflow to a bignum). Alternatively, use `Array#hash`, like `[@data1, @data2].hash`, say.
Marc-André Lafortune
Good point. Adding individual hashes together also has the danger that the same sum could result from different individual hashes (3 + 2 = 5 and 1 + 4 = 5). Using Array#hash as Marc-Andre suggests would make the solution more complete.
Mark
They are not the same object, but they still can be defined as 'equal'. For example, two strings with the same content could not be the same object, still you can use them as keys.
Valentin Rocher
Poul
I would strongly recommend implementing both hash and eql?. BTW, if this works for you, can you accept this answer? Thx
Mark
A: 

Add a method called 'hash' to your class:

class Foo
  def hash
    return whatever_munge_of_instance_variables_you_like
  end
end

This will work the way you requested and won't generate different hash keys for different, but identical, objects.