This may be because foo[bar]+=baz is syntactic sugar for foo[bar]=foo[bar]+baz when foo[bar] on the right hand of = is evaluated it returns the default value object and the + operator will not change it. The left hand is syntactic sugar for the []= method which won't change the default value.

Note that this doesn't apply to foo[bar]<<=bazas it'll be equivalent to foo[bar]=foo[bar]<<baz and <<will change the default value.

Also, I found no difference between Hash.new{[]} and Hash.new{|hash, key| hash[key]=[];}. At least on ruby 2.1.2 .

Nice explanation. It seems like on ruby 2.1.1 Hash.new{[]} is the same as Hash.new([]) for me with the lack of expected << behavior (though of course Hash.new{|hash, key| hash[key]=[];} works). Weird small things breaking all the things :/
–
butterywombatOct 14 '14 at 19:18

How can I use separate array instances for each new hash?
–
Valentin VasilyevApr 23 '10 at 12:40

4

That block version gives you new Array instances on each invocation. To wit: h = Hash.new { |hash, key| hash[key] = []; puts hash[key].object_id }; h[1] # => 16348490; h[2] # => 16346570. Also: if you use the block version that sets the value ( {|hash,key| hash[key] = []}) rather than the one that simply generates the value ({ [] }), then you only need <<, not <<= when adding elements.
–
James A. RosenApr 23 '10 at 13:15