I don’t have an answer, but trying out the code in JRuby, I can see that
the default value for bar becomes simply the products array after the
inject() method is used. One more thing that requires an explanation.
You can see this by appending this line to your code:
Returns a new, empty hash. If this hash is subsequently accessed by
a key that doesn't correspond to a hash entry, the value returned
depends on the style of +new+ used to create the hash. In the first
form, the access returns +nil+. If _obj_ is specified, this single
object will be used for all _default values_. If a block is
specified, it will be called with the hash object and the key, and
should return the default value. It is the block's responsibility
to store the value in the hash if required.
h = Hash.new("Go Fish")
h["a"] = 100
h["b"] = 200
h["a"] #=> 100
h["c"] #=> "Go Fish"
# The following alters the single default object
h["c"].upcase! #=> "GO FISH"
h["d"] #=> "GO FISH"
h.keys #=> ["a", "b"]
The key line is:
8It is the block’s responsibility to store the value in the hash if
required.
Because your block does not assign the array to a hash key, the array is
discarded.
Sorry, I pasted the ri output on top of the first part of my post, which
said something to the effect of:
My question: why is bar empty?
…because h[non_existent_key] sends an array that is unassociated with
any hash to the block. In other words, creating a hash with a default
value does not cause a key/value pair to be created in the hash when a
non-existent key is accessed.
Sorry, I pasted the ri output on top of the first part of my post, which
said something to the effect of:
My question: why is bar empty?
…because h[non_existent_key] sends an array that is unassociated with
any hash to the block. In other words, creating a hash with a default
value does not cause a key/value pair to be created in the hash when a
non-existent key is accessed.
It was probably best that first sentence was erased. Here is what I was
trying to say:
h = Hash.new([])
result = h[“A”]
p result
–output:–
[]
p h
–output:–
{}
When you write:
h[p.category] << p
The example above demonstrates that is equivalent* to:
[] << p
…and that simply appends an object to an empty array, and does nothing
to the hash.
And you are in even worse shape than you realize. If you take the empty
array that is returned as the default value and append an object to the
array, and then manually assign the array to a key in the hash:
h = Hash.new([])
h[“A”] = h[“A”] << 10 #==>[10]
h[“B”] = h[“B”] << 20 #==>[20]
Look what happens:
p h
{“A”=>[10, 20], “B”=>[10, 20]}
Yep, ruby hands you a reference to the same array over and over again.