how does default_proc work
ruby
Solution
You are taking it the wrong way. `&h` is not a meaningful unit in this context. It is `&` attached to `h.default_proc`. That is a proc `h.default_proc` turned into a block. Similar thing applies to the splat operator `*`. The associative precedence of `&` and `*` is always the last. The reason is clear: it does not make sense otherwise.
Suppose you have:
config = Hash.new() # or `{}`
then, whenever you access `config` with an un-existing key, it will return `nil`, so
config[:production][:database]
will return an error because the method `[]` is not defined on `config[:production]`, which equals `nil`. When you do:
config = Hash.new do |h,k|
h[k] = Hash.new()
end
then, it will be ensured that when you access `config` with an un-existing key, it creates a new hash as a value. So
config[:production][:database]
will now be okay because the method `[]` is defined on `config[:production]`, which equals the newly created hash `{}`. But still,
config[:production][:database][:adapter]
will return an error because the method `[]` is not defined on `config[:production][:database]`, which equals `nil`. If you instead have:
config = Hash.new do |h,k|
h[k] = Hash.new(&h.default_proc)
end
then, that means that, when you access `config` with an un-existing key like:
config[:production]
the hash that is created this time will have a `default_proc` set to the same one as `config`, which means that
config[:procuction][:database]
is not a hash that returns `nil` to a non-existing key call, but a hash that returns another hash to a non-existing key call. So this time,
config[:production][:database][:adapter]
will not return an error. Similar thing happens with an arbitrary depth within the hash.
Problem
The following code was taken from a RubyTapas screencast, but it wasn't explained sufficiently for a person of my experience. Setting up a hash like this ``` config = Hash.new do |h,k| h[k] = Hash.new(&h.default_proc) end ``` allows one to set and access values in the following way ``` config[:production][:database][:adapter] = 'mysql' puts config[:production][:database][:adapter] # => "mysql" ``` When I do ``` puts config.inspect ``` It reveals a nested hash. ``` {:production=>{:database=>{:adapter=>"mysql"}}} ``` However, if I modify the code (to just play around with it) to remove &h.default_proc ``` config = Hash.new do |h,k| h[k] = Hash.new() #&h.default_proc removed from parameter end ``` I get this error ``` undefined method `[]=' for nil:NilClass (NoMethodError) ``` I don't get what is happening with Hash.new(&h.default_proc), when, for example, I do this ``` config[:production][:database][:adapter] = 'mysql' puts config[:production][:database][:adapter] # => "mysql" ``` Can you break down that, explaining in detail how the block `&hdefault_proc` is working in this context. Please also explain if you can when the proc is getting called. Why is the proc necessary to make this work ``` config[:production][:database][:adapter] = 'mysql' ``` and how does the proc get called? I thought you have to do proc.call to actually call the proc. Thanks in advance