# Problem with hash (again)

**URL:** <https://www.ruby-forum.com/t/problem-with-hash-again/172658>\
**Category:** Ruby\
**Created:** [July 24, 2009, 8:41pm UTC](https://www.ruby-forum.com/t/problem-with-hash-again/172658 "2009-07-24T20:41:45Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![tbaustert](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ecae2f/32.png) [@tbaustert](https://www.ruby-forum.com/u/tbaustert)\
**Post date:** [July 24, 2009, 8:41pm UTC](https://www.ruby-forum.com/t/problem-with-hash-again/172658/1 "2009-07-24T20:41:45Z")

</div>

It says in the documentation to hash function  
([class Object - RDoc Documentation](http://ruby-doc.org/core/classes/Object.html#M000337)):

“Any hash value that exceeds the capacity of a Fixnum will be truncated  
before being used.”

From this I understand that it’s OK for my object to return a Bignum.  
But no:

irb(main):116:0\> o=Object::new  
=\> #Object:0x7f81464  
irb(main):117:0\> def o.hash;89624894967898529964558;end  
=\> nil  
irb(main):118:0\> o.hash  
=\> 89624894967898529964558  
irb(main):119:0\> [o].hash  
RangeError: bignum too big to convert into `long' from (irb):119:in `hash’

My o can be used as a key in Hash but computing the hash of Array with  
it inside fails. So now:

1. Isn’t it inconsistent with the description? It says that hash will be  
truncated before being used, so it should be truncated before being used  
to calculate the hash of the array.
2. What is the walkaround? How to check if a value has already exceeded  
the capacity of Fixnum, and how to truncate it manually?

It was TPR speaking, from Ruby 1.9.1p0 on Windows, thanks for listening.

---

<div class="post-metadata">

**Author:** ![tbaustert](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ecae2f/32.png) [@tbaustert](https://www.ruby-forum.com/u/tbaustert)\
**Post date:** [July 24, 2009, 9:06pm UTC](https://www.ruby-forum.com/t/problem-with-hash-again/172658/2 "2009-07-24T21:06:57Z")

</div>

On Fri, Jul 24, 2009 at 2:41 PM, Thomas B.[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> 1. Isn’t it inconsistent with the description? It says that hash will be  
> truncated before being used, so it should be truncated before being used  
> to calculate the hash of the array.

The documentation for Object#hash says that. You’re experiencing  
this error with Array#hash  
Not that I’m implying this is necessarily ‘ok’ but you had the same  
mistake in your last post, reading Object’s docs and applying them to  
another class.

---

<div class="post-metadata">

**Author:** ![tbaustert](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ecae2f/32.png) [@tbaustert](https://www.ruby-forum.com/u/tbaustert)\
**Post date:** [July 24, 2009, 9:20pm UTC](https://www.ruby-forum.com/t/problem-with-hash-again/172658/3 "2009-07-24T21:20:55Z")

</div>

Gregory B. wrote:

> Not that I’m implying this is necessarily ‘ok’ but you had the same  
> mistake in your last post, reading Object’s docs and applying them to  
> another class.

I think that if there is a description of hash or eql? or any other  
method for Object and no description of this method in class X (X \<  
Object, of course) then the contract and general behaviour is inherited.  
So it’s not my mistake. If I want to learn about Float#hash and there’s  
no description of hash under Float then I search for the description in  
Float’s ancestors, until I find it, no further than under Object. And it  
should apply to Floats as well.

Apart from that, if you prefer, I can call {[o]=\>0}, and not directly  
call Array#hash, and I get the same error of course. And now you cannot  
say that I try to apply what I read about Object to Array, because now,  
from the user point of view, there’s simply something wrong, it doesn’t  
work even though I did everything OK, I redefined o.hash in a way that  
is consistent with the reference for Object#hash.

For me that’s a bug.

---

<div class="post-metadata">

**Author:** ![tbaustert](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ecae2f/32.png) [@tbaustert](https://www.ruby-forum.com/u/tbaustert)\
**Post date:** [July 24, 2009, 9:40pm UTC](https://www.ruby-forum.com/t/problem-with-hash-again/172658/4 "2009-07-24T21:40:40Z")

</div>

Thomas B. wrote:

> For me that’s a bug.

Do a service for the community and report it here:  
[http://redmine.ruby-lang.org/](http://redmine.ruby-lang.org/).

Thanks!

---

<div class="post-metadata">

**Author:** ![tbaustert](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ecae2f/32.png) [@tbaustert](https://www.ruby-forum.com/u/tbaustert)\
**Post date:** [July 24, 2009, 10:13pm UTC](https://www.ruby-forum.com/t/problem-with-hash-again/172658/5 "2009-07-24T22:13:06Z")

</div>

On Jul 24, 2009, at 2:41 PM, Thomas B. wrote:

> 1. What is the walkaround? How to check if a value has already  
> exceeded  
> the capacity of Fixnum, and how to truncate it manually?

Something like this might work…

Fixnum\_max = (2\*\*30 - 1)

def hash  
compute\_bignum % Fixnum\_max  
end

But I think it would make sense to avoid generating bignums  
in the first place.

Gary W.

---

<div class="post-metadata">

**Author:** ![tbaustert](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ecae2f/32.png) [@tbaustert](https://www.ruby-forum.com/u/tbaustert)\
**Post date:** [July 24, 2009, 10:49pm UTC](https://www.ruby-forum.com/t/problem-with-hash-again/172658/6 "2009-07-24T22:49:23Z")

</div>

On Fri, Jul 24, 2009 at 3:21 PM, Thomas B.[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Apart from that, if you prefer, I can call {[o]=\>0}, and not directly  
> call Array#hash, and I get the same error of course. And now you cannot  
> say that I try to apply what I read about Object to Array, because now,  
> from the user point of view, there’s simply something wrong, it doesn’t  
> work even though I did everything OK, I redefined o.hash in a way that  
> is consistent with the reference for Object#hash.

And then you’d _still_ be talking about Array#hash.

> > def o.hash; 89624894967898529964558;end  
> > =\> nil  
> > a = { o =\> 1 } # this works!  
> > =\> {#Object:0x248d6c=\>1}  
> > a = { [o] =\> 1 }  
> > RangeError: bignum too big to convert into `long' from (irb):23:in `hash’  
> > from (irb):23

Just because obj.hash gets called farther down the chain isn’t an  
indication of how anything ought to work.

To be clear, I think it’s basically a bug, for sure. But I think the  
bug is that Array#hash doesn’t do this truncation trick that  
Object#hash claims, which doesn’t tell me anything about Object#hash’s  
documentation.  
So I’m not disagreeing with you, I’m just expressing the concern that  
the issue is probably in Array, not Object.

-greg

---

<div class="post-metadata">

**Author:** ![tbaustert](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ecae2f/32.png) [@tbaustert](https://www.ruby-forum.com/u/tbaustert)\
**Post date:** [July 24, 2009, 10:47pm UTC](https://www.ruby-forum.com/t/problem-with-hash-again/172658/7 "2009-07-24T22:47:38Z")

</div>

2009/7/24 Thomas B. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> It says in the documentation to hash function  
> ([class Object - RDoc Documentation](http://ruby-doc.org/core/classes/Object.html#M000337)):
> 
> “Any hash value that exceeds the capacity of a Fixnum will be truncated  
> before being used.”  
> […]

Hello,

the statement you are quoting from the documentation is preceded by  
the sentence “The hash value is used by class Hash.”, which, in my  
opinion, makes it quite clear, that the following information about  
the hash value being truncated applies only to how class Hash uses the  
hash value, not to the behaviour of any other class such as Array.  
This also seems reasonable, since the class Object has no way of  
ensuring that every caller of its hash method processes the values  
returned by that method in a certain way.

> […]  
> 2. What is the walkaround? How to check if a value has already exceeded  
> the capacity of Fixnum, and how to truncate it manually?  
> […]

Since, according to the documentation, instances of Fixnum are signed  
numbers fitting in a machine word minus one bit, and the instance  
method Fixnum#size should return the size of a machine word in bytes,  
you could do the following to truncate values to the fixnum range:

some\_large\_value & (2 \*\* (8 \* 0.size - 2) - 1)

However, it is probably better to avoid generating numbers outside of  
the fixnum range in the first place, since that will save unnecessary  
computation time.

cu,  
Thomas

---

<div class="post-metadata">

**Author:** ![tbaustert](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ecae2f/32.png) [@tbaustert](https://www.ruby-forum.com/u/tbaustert)\
**Post date:** [July 24, 2009, 11:40pm UTC](https://www.ruby-forum.com/t/problem-with-hash-again/172658/8 "2009-07-24T23:40:21Z")

</div>

On Jul 24, 2009, at 4:45 PM, Thomas C. wrote:

> some\_large\_value & (2 \*\* (8 \* 0.size - 2) - 1)

Bitwise AND is better than my integer division  
suggestion in a previous post but then again they  
are probably all slow with a Bignum operand.

Gary W.

---

<div class="post-metadata">

**Author:** ![tbaustert](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ecae2f/32.png) [@tbaustert](https://www.ruby-forum.com/u/tbaustert)\
**Post date:** [July 24, 2009, 10:54pm UTC](https://www.ruby-forum.com/t/problem-with-hash-again/172658/9 "2009-07-24T22:54:04Z")

</div>

On Fri, Jul 24, 2009 at 4:48 PM, Gregory  
Brown[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> To be clear, I think it’s basically a bug, for sure. But I think the  
> bug is that Array#hash doesn’t do this truncation trick that  
> Object#hash claims, which doesn’t tell me anything about Object#hash’s  
> documentation.  
> So I’m not disagreeing with you, I’m just expressing the concern that  
> the issue is probably in Array, not Object.

To further illustrate:

> > class Array  
> > def hash  
> > 42 # terrible idea  
> > end  
> > end  
> > =\> nil  
> > a = { o =\> 1 }  
> > =\> {#Object:0x248d6c=\>1}
