Incorrect -0.0.hash - Ruby bug

Hello. I just found a bug in Ruby, version 1.9.1p0, Windows.

In the rdoc to Object#hash we read
(class Object - RDoc Documentation):

“This function must have the property that a.eql?(b) implies a.hash ==
b.hash.”

Now see:

irb(main):214:0> z=0.0
=> 0.0
irb(main):215:0> nz=-0.0
=> -0.0
irb(main):216:0> z.eql?(nz)
=> true
irb(main):217:0> z.hash
=> 1041500564
irb(main):218:0> nz.hash
=> -434138511

So the class Float does not fully follow the #hash contract. Well, isn’t
that strange?

TPR.

Morning Thomas,

On Wed, Jul 22, 2009 at 9:24 AM, Thomas B. [email protected] wrote:

Hello. I just found a bug in Ruby, version 1.9.1p0, Windows.

In the rdoc to Object#hash we read
(class Object - RDoc Documentation):

“This function must have the property that a.eql?(b) implies a.hash ==
b.hash.”

Actually Float overrides both #eql? and #hash so the contract is not
applicable inside that class. Is that the best option in the world?? -
probably not - but that would make it a non bug in theory.

John

2009/7/22 John W Higgins [email protected]

b.hash."

Actually Float overrides both #eql? and #hash so the contract is not
applicable inside that class. Is that the best option in the world?? -
probably not - but that would make it a non bug in theory.

Is there a reason for this? Perhaps the inexact nature of Floats means
you
ought not to use them as hash keys?

On 7/22/09, John W Higgins [email protected] wrote:

“This function must have the property that a.eql?(b) implies a.hash ==
b.hash.”

My understanding is that this relationship shall be kept for the
purpose of correct hash key behavior

553/60 > ruby -v -e ‘p( {0.0 => 42}[-0.0] )’
ruby 1.9.1p243 (2009-07-16 revision 24175) [i686-linux]
nil

which is not nice.
That said floats as hash keys are a bad idea of course because of
equality is not very well defined anyway.

Cheers
Robert

Actually Float overrides both #eql? and #hash so the contract is not
applicable inside that class. Is that the best option in the world?? -
probably not - but that would make it a non bug in theory.

John


Toutes les grandes personnes ont d’abord été des enfants, mais peu
d’entre elles s’en souviennent.

All adults have been children first, but not many remember.

[Antoine de Saint-Exupéry]

James C. wrote:

Is there a reason for this? Perhaps the inexact nature of Floats means
you
ought not to use them as hash keys?

In my program it’s very convenient to use float vectors as keys because
I create a graph where points (vertices) are calculated numerically as
cross points of lines and so on (that’s why I get -0.0 from time to
time). I round the floats to 8 decimal digits, and added a quick fix for
the hash:

alias :hash_orig :hash
def hash
eql?(0.0) ? 0.0.hash_orig : hash_orig
end

and it works like it should, so I think it was a good idea to use them
as keys :slight_smile:

Actually Float overrides both #eql? and #hash so the contract is not
applicable inside that class. Is that the best option in the world?? -
probably not - but that would make it a non bug in theory.

I’d assume it overrides both methods in order to fulfill the contract
not to break it. Contract are there so that people can rely on it.
Breaking it is an error.