From: Jacob Fugal Date: 2006-06-28T05:49:20+09:00 Subject: Re: Ruby and Java equality usage On 6/27/06, Molitor, Stephen L wrote: > >>>> Jacob Fugal wrote: > > > Is it true then that a.eql?(b) only if a.hash == b.hash? > > Yes. But not necessarily the vice versa. If a.eql?(b) is true, then > a.hash == b.hash must also be true. And if a.hash != b.hash, then > a.eql?(b) is necessarily false. However if a.hash == b.hash, then > a.eql?(b) may be true or false. (The above is all assuming proper > implementations of hash and eql?.) I understand the "not vice versa" (that's why I used "only if" in the clause above :). I'm still not convinced that a.eql?(b) must imply a.hash == b.hash. I'm willing to be convinced, but I haven't heard yet an argument as to *why* -- only arguments along the lines of "that's the way it is". The way I see it, from looking through hash.c and st.c in the core, there is no contract on the value of a.eql?(b) when a.hash != b.hash. As far as I can tell, implementing MyClass#eql? as: class MyClass def eql?(other) raise "Oops!" unless self.hash == other.hash return false end end will never raise the exception in normal use of the Hash class (I'm assuming that people follow the rules and aren't using eql? explicitly). That's why I asked the following: > > What's the damage in a.eql?(b) returning true when in different > > buckets? > > That will never happen. If a and b have different hashes then they go > in different buckets. And if their hashes are different they are not > equivalent (not eql?). But it *will* happen, if I don't follow your definition of a "proper" implementation of eql?. I can understand the pushback in your second sentence. Semantically, it doesn't make sense for two objects that claim to be eql? to be hashed into different buckets. But relying on the exclusive manner in which eql? is called, that shouldn't matter It's the same as implementing a function (math) with a limited domain. What's the output of the function (code) when I give it an invalid input? If I can guarantee that an invalid input will never be given, it doesn't matter. > > Why doesn't the default implementation of Object#eql? just use #== > > internally? > > Good question! Or to put it another way why do we need separate == and > eql? methods? The only rationale I can think of is to completely > separate the hash related methods (eql? and hash) from ==. So I can > override == knowing that I won't be changing hash behavior at all. > Except that if I'm overriding == I would usually want to change the hash > related behaviors to be consistent with my new concept of equivalence! I disagree that questioning the existence of eql? is the same as what I'm suggesting above. I understand perfectly well why eql? exists separate from ==. eql? serves exactly one purpose: determining whether two objects that get hashed into the same bucket should be considered the same key or a different key. I can understand as well that there are times when that determination will be separate from the determination of whether the objects are "equal" (==). So I do believe that the eql? method is necessary. However, I don't see why -- apart from purity in the insistence that a.eql?(b) only if a.hash == b.hash -- the *default* behavior of eql? can't be the same as ==. And since I only see that one reason -- purity -- this is my question: Would it introduce bugs if a.eql?(b) were to return true when a.hash != b.hash? Jacob Fugal