Problem with hash (again)

It says in the documentation to hash function
(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:inhash’

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.

On Fri, Jul 24, 2009 at 2:41 PM, Thomas B.[email protected] 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.

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.

Thomas B. wrote:

For me that’s a bug.

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

Thanks!

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.

On Fri, Jul 24, 2009 at 3:21 PM, Thomas B.[email protected] 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:inhash’
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

2009/7/24 Thomas B. [email protected]:

It says in the documentation to hash function
(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

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.

On Fri, Jul 24, 2009 at 4:48 PM, Gregory
Brown[email protected] 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}

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs