A hash that contains itself under :b
Question
What's the return value of the following Ruby code?
hash = {a: 1}
hash[:b] = hash
hash[:b][:b][:b][:a] # => ???
The correct answer is
-
nil -
{a: 1, b: {...}} -
1Correct -
SystemStackError
Explanation
TL;DR
hash[:b] = hash stores a reference to the hash inside itself, not a copy. Every [:b] lookup therefore returns the original hash, so hash[:b][:b][:b] is still hash, and the final [:a] reads the original pair: 1.
Step by step
hash = {a: 1}
hash[:b] = hash
hash[:b].equal?(hash) # => true
hash[:b][:b].equal?(hash) # => true
hash[:b][:b][:b].equal?(hash) # => true
hash[:b][:b][:b][:a] # => 1
Ruby variables and hash values hold references to objects. The assignment does not expand hash into a nested structure; it just makes the value under :b point back at the same object. Chaining [:b] any number of times, three or three thousand, lands on the same hash, and [:a] on that hash is 1.
Each [:b] is a single, ordinary hash lookup that returns immediately, so nothing recurses and no SystemStackError is possible here. The structure is cyclic; the access is not.
Edge cases
inspect has to deal with the cycle, and it does so with a placeholder instead of recursing forever:
hash = {a: 1}
hash[:b] = hash
hash.inspect # => "{a: 1, b: {...}}"
The {...} marks the point where the hash references itself. Operations that must fully traverse the structure are the dangerous ones: hash.to_a is fine (it is shallow), but recursively walking or deep-duplicating a self-referencing hash without cycle detection will loop or overflow the stack.
Share this quiz
Comments
No comments yet. Be the first.