irb(main):039:0> hash = Hash.new []
I assume here that [] is the default value, right?
=> {}
irb(main):040:0> hash['abc'] << 3
=> [3]
irb(main):041:0> hash.keys
=> []
irb(main):042:0> hash['def']
=> [3]
Since I have created a key/value pair with hash['abc'] << 3, why
hash.keys show nothing?
Because you haven't set anything in the hash. That is,
hash['abc'] = 3
is equivalent to:
hash.[]=('abc', 3)
On the other hand, what you've done is:
hash['abc'] << 3
That's equivalent to:
hash.[]('abc') << 3
I don't know if that helps, but that's the difference. Let me put it this way
-- suppose you hadn't changed the default value:
irb(main):001:0> hash = {}
=> {}
irb(main):002:0> hash['abc']
=> nil
irb(main):003:0> hash.keys
=> []
Do you understand why that works the way it does? But there's nothing special
about nil here, it's just the, erm, _default_ default value -- it's what Hash
uses as a default value if you don't specify one.
And, why hash['abc'] << 3 changed the hash's default value (which
should be an empty array)?
Because you set the default value to [], which creates an empty array object,
once. The hash is just assigning it each time. Think of it this way:
irb(main):004:0> default = []
=> []
irb(main):005:0> a = default
=> []
irb(main):006:0> b = default
=> []
irb(main):007:0> a << 3
=> [3]
irb(main):008:0> b
=> [3]
What you really want is the block notation of creating a hash, which lets you
actually specify some code that's run to create a default value, as Bill Kelly
says. The reason his code works is that when you try to access a value that
doesn't exist, it actually runs some code which sets that value:
h = Hash.new {|h,k| h[k] = []}
It wouldn't work at all if you just did this:
h = Hash.new {|h,k| []}
That would at least give you a new array each time, but since it wouldn't set
it, you'd see weird things:
irb(main):010:0> h['abc'] << 3
=> [3]
irb(main):011:0> h['abc']
=> []
irb(main):012:0> h.keys
=> []