Reputation: 4545
Came across the following weird behaviour in ruby 1.8.6, in 1.8.7 it seems to be working correctly. Does anyone know what would have caused this?
h = {}
key_1 = {1 => 2}
key_2 = {1 => 2}
h[key_1] = 3
p key_1 == key_2 # => true
p h.has_key?(key_2) # => expect true, get false, wtf?
I had thought that it would be caused by the implementation of the hash method on the Hash class.
p [key_1.hash, key_2.hash] # => [537787070, 537787060] (different)
but even if I override the hash method of Hash
class Hash
def hash
return self.keys.hash + self.values.hash
end
end
p [key_1.hash, key_2.hash] # => [8,8] (same
p h.has_key?(key_2) # => false
codepad link to online ruby 1.8.6 interpreter results: http://codepad.org/7nCYMP4w
Upvotes: 4
Views: 2823
Reputation: 66921
This is fixed in 1.8.7+ but you can monkey patch 1.8.6 to do it right, too ex: https://github.com/rdp/sane/blob/master/lib/sane/hash_hashes.rb
Upvotes: 1
Reputation: 6856
The answer is because in Ruby 1.8.6 the hash coding algorithm was broken for hash keys.
http://paulbarry.com/articles/2009/09/14/why-rails-3-will-require-ruby-1-8-7
Edit: Here is an example that shows that ruby does not call .hash internally:
class Hash
def hash
raise
end
end
{1=>1}.hash
RuntimeError:
from (irb):12:in `hash'
from (irb):17
h = {1=>2}
{1=>2}
h[1]
2
Ruby 1.8.6 is broken in this respect, and if there were a pure Ruby way to do it (such as opening Hash
, people would do it. It was fixed in 1.8.7
Upvotes: 2