4

The following code creates a hashmap and places it inside of itself.

hash = {}
hash[hash] = hash
hash.keys.first == hash # true
hash.values.first == hash # true
hash[hash] # nil??
hash.key?(hash) # False
hash[hash.keys.first] # nil???
hash[{}] # nil

Can anyone explain these results to me? They seem very counterintuitive.

Philip M
  • 149
  • 1
  • 6
  • Regarding your second line (which causes all the problems), see [Hash#\[\]=](http://ruby-doc.org/core-2.4.0/Hash.html#method-i-5B-5D-3D), specifically, "key should not have its value changed while it is in use as a key". – Cary Swoveland May 18 '18 at 21:25

1 Answers1

5

Mutable objects (such as Array and Hash) are basically improper for a hash key if you may modify them. In this case, the hash was modified at the point of insertion (since it was inserted into itself!) and has therefore been left in an improper state.

If it is absolutely necessary, you can use Hash#rehash to rectify the object state:

hash = {}
hash[hash] = hash

hash.rehash # !!!!

hash.keys.first == hash # true
hash.values.first == hash # true
hash[hash] #=> {{...}=>{...}}
hash.key?(hash) # true
hash[hash.keys.first] #=> {{...}=>{...}}
hash[{}] # nil
Tom Lord
  • 27,404
  • 4
  • 50
  • 77
  • Any idea why an exception is not raised at line #2? You may want to show the weird return value for that line: (`{{...}=>{...}}`) . – Cary Swoveland May 18 '18 at 21:30