Reputation: 769
So I have a class wherein I need to override the equality operators. This is not so hard. But the custom equality operators aren't used unless my_obj.hash is equal for two objects being compared. so we need to override hash()
I'm kind of stuck on the best way to do this. My object embeds three other object instances. I see by example that for simple instance vars you can just take a hash of the vars themselves:
[var1, var2, var3].hash
More specifically, my class has instance vars for three embedded objects, let's call them:
A B1 B2
Two instances of my object are equal if
object1.B1 == object2.B1 && object1.B2 == object2.B2 ||
object1.B1 == object2.B2 && object1.B2 == object2.B1
In other words, the collection of B1 and B2 has the same two objects in it, regardless of which specific vars they're assigned to.
B1 and B2 have a custom equality mechanism as well.
I'm just not clear on the best strategy for overriding hash() here.
Sorry if the example is abstract, I'm trying to avoid posting a lot of code.
Upvotes: 2
Views: 611
Reputation: 87396
Try using a Set instead of an array so the order doesn't matter. You have to have this line at the top:
require 'set'
Then make a Set containing both objects and use it to help implement the equality operator and hash method. I assume Set#hash behaves correctly and your can use it in your hash method. Set#== can be used to simplify your equality operator.
http://www.ruby-doc.org/stdlib-2.1.4/libdoc/set/rdoc/Set.html
Upvotes: 2
Reputation: 13612
Are your B1
and B2
objects sortable? If so, here's an easy implementation of your hash
method:
class MyClass
def hash
return [self.B1, self.B2].sort.hash
end
end
If they aren't currently sortable and it makes no sense to sort them by any inherent value, you could always just sort by object_id
:
class BClass
include Comparable
def <=> (other)
case other
when BClass then return (self.object_id <=> other.object_id)
else return nil
end
end
end
This enables your B1
and B2
objects to sort themselves versus each other, while throwing "ArgumentError: comparison of X with Y failed" versus instances of any other class.
If you're going the route of using object_id
, though, it may just be easier to implement your hash
method using that to begin with:
class MyClass
def hash
return [self.B1.object_id, self.B2.object_id].sort.hash
end
end
but this will mean only self-same objects will correctly turn up as equal, and not just objects that "look" alike. To understand what I mean, compare the following:
# Comparison of look-alike objects
"a".object_id == "a".object_id # => false
# Comparison of self-same objects
a = "a"
a.object_id == a.object_id # => true
Upvotes: 1
Reputation: 2267
I assume the hash value can be any object as long as it is unique in each object in your case. If that assumption is correct, how about defining the object hash()
method returns as an array, for example?
I am not 100% clear what you are trying to achieve. But I have interpreted the order of self.B1
and self.B2
does not matter. Then this is a possibility:
def hash
[self.B1.hash, self.B2.hash].sort
end
Then you can compare hash()
of two objects with
(my_obj1.hash == my_obj2.hash)
Upvotes: -1