Every “default” element of hsh contains a reference to the ary
object. Similarly, in your original example, every default element of h contained a reference to the unnamed array object.
At a guess as to the first part:
h = Hash.new([])
1. you create an unnamed array object
2. you create a hash object, whose “default value” is a reference to
that array object
h[:a] << 2
3. h has no key :a, so h[:a] returns the default object (the
unnamed array) above
4. you call << 2 on that default object; so the unnamed array now
has one element
h[:a] << 3
5. (as above, now it has two elements)
h[:a] # => [2, 3]
6. h still has no key :a, so h[:a] returns the default object (the
unnamed array) above, which has the two elements you assigned it
h # => {}
7. at no point above did you add an element to h; all you did is
get an element (which didn’t exist, so you always got the default),
so h remains empty
h[:b] << 2
8. like above: h has no key :b, so h[:b] returns the default object
9. you call << 2 on that object, so now it has 3 elements
h[:b] # => [2, 3, 2]
10. h still has no key :b, so h[:b] returns the default object,
The documentation is very specific about the difference between
Hash.new() and Hash.new {}, providing in the first case a single
default object, whereas in the second case a fresh object is returned.
You should study the given examples.
Watch out using Hash.new([]) - you have to be aware of what it does. It
sets the hash’s default object, and there is only one of them per hash,
and you might not see the expected list of keys because you are updating
the Hash’s default object: