Reputation: 409
I learned from this answer here that this is possible:
h = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
h['bar'] # => {}
h['tar']['star']['par'] # => {}
Can someone explain how it works?
Upvotes: 3
Views: 5392
Reputation: 2232
Hashes have a thing called a default_proc
, which is simply a proc that Ruby runs when you try to access a hash key that doesn't exist. This proc receives both the hash itself and the target key as parameters.
You can set a Hash's default_proc
at any time. Passing a block parameter to Hash.new
simply allows you to initialize a Hash and set its default_proc
in one step:
h = Hash.new
h.default_proc = proc{ |hash, key| hash[key] = 'foo' }
# The above is equivalent to:
h = Hash.new{ |hash, key| hash[key] = 'foo' }
We can also access the default proc for a hash by calling h.default_proc
. Knowing this, and knowing that the ampersand (&
) allows a proc passed as a normal parameter to be treated as a block parameter, we can now explain how this code works:
cool_hash = Hash.new{ |h, k| h[k] = Hash.new(&h.default_proc) }
The block passed to Hash.new
will be called when we try to access a key that doesn't exist. This block will receive the hash itself as h
, and the key we tried to access as k
. We respond by setting h[k]
(that is, the value of the key we're trying to access) to a new hash. Into the constructor of this new hash, we pass the "parent" hash's default_proc
, using an ampersand to force it to be interpreted as a block parameter. This is the equivalent of doing the following, to an infinite depth:
cool_hash = Hash.new{ |h, k| h[k] = Hash.new{ |h, k| h[k] = Hash.new{ ... } } }
The end result is that the key we tried to access was initialized to a new Hash, which itself will initialize any "not found" keys to a new Hash, which itself will have the same behavior, etc. It's hashes all the way down.
Upvotes: 16
Reputation: 414
In this code you create hashes by chain, so that any link of chain would have same default_proc
So, default_proc
of h
and h['bar']
and so far will be the same - it will return new instance of Hash
with this default_proc
Upvotes: 1