If you specify a parameter for Hash.new the SAME object will be used for any default value (see documentation). If you modify it, it will be modified for all default values afterwards. Try to see what the value will be returned for r[:a] if you do it again. I bet it will be {:c => 10}. As well as for r[:c], r[10] and so on.
Gennady.
···
On Aug 28, 2005, at 21:16, Trans wrote:
irb(main):006:0> def r
irb(main):007:1> @r ||= Hash.new({})
irb(main):008:1> end
=> nil
irb(main):009:0> r[:a]
=> {}
irb(main):010:0> r[:b][:c] = 10
=> 10
irb(main):011:0> r
=> {}
irb(main):012:0> r[:b]
=> {:c=>10}
irb(main):013:0>
Please explain how r is empty but r[:b] exists. Thank You.
...
Please explain how r is empty but r[:b] exists. Thank You.
# To summarize:
h = Hash.new({})
h[1][2] = 3
h #=> {}
h.default #=> {2=>3}
So you've added to the default object. It might be helpful to note another
wrong way to do this:
h = Hash.new { {} }
h[1][2] = 3
h #=> {}
h.default #=> {}
Different, because default now returns a new hash every time.
But, to answer the implied question, "what is the code that will do what I
intend?" there are a few ways to do this:
# Just one level of magic new hashes
h = Hash.new {|hash, key| hash[key] = {} }
h[1][2] = 3
h #=> {1=>{2=>3}}
h[1][2][3] = 4 # Error (calling = on nil)
# Auto-vivifying hash: using Hash subclass
class X < Hash
def default(key = nil)
self[key] = self.class.new
end
end
h = X.new #=> {}
h[1][2][3] = 4
h #=> {1=>{2=>{3=>4}}}