I'd like my class to be complete for several anticipated scenarios, including object comparison. My class is Hash
-like in that it has a method to_hash
, on which many of my class-completing methods are based. For example:
class Hashlike
def == other
if other.respond_to?(:to_hash)
to_hash == other.to_hash
end
end
end
It seems overkill to override Hash#==
just to inject similarity into the message's superchain:
class Hash
def == other
# Flip the comparison
other.is_a?(Hashlike) ? other == self : super
end
end
This will end up in stacktraces everywhere for entirely irrelevant issues. This feels invasive.
Is there a preferred or less invasive way to make Hash
aware of my Hashlike
's eligibility for comparison? And in general, is there a convention for extending core objects (Hash
, Array
) to receive core interface messages (==
, nil?
, <==>
) and be aware of custom classes without leaving fingerprints all over their superchains?
Update:
The only optimization that occurs to me is to make the override call super first in the hopes of not choking a potentially heavily-used method with early conditional branching:
class Hash
def == other
# Lazily delay the comparison
super or (other == self if other.is_a?(Hashlike))
end
end
Some careful benchmarking (to the order of 1 billion comparisons) suggests that using either approach performs just as well as ruby's default of reversing the comparison if to_hash
is defined on the received object, as mentioned in the answer below.