>>>> 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
···
On 6/27/06, Molitor, Stephen L <Stephen.L.Molitor@erac.com> wrote: