The difference in your code isn't about <<
vs. push
, it's about the fact that you re-assign in one case and don't in the other. The following two pieces of code are equivalent:
@connections = Hash.new []
@connections[1] = @connections[1].push(2)
puts @connections # => {1=>[2]}
@connections = Hash.new []
@connections[1] = (@connections[1] << 2)
puts @connections # => {1=>[2]}
As are these two:
@connections = Hash.new []
@connections[1].push(2)
puts @connections # => {}
@connections = Hash.new []
@connections[1] << 2
puts @connections # => {}
The reason that re-assignment makes a difference here is that accessing a default value, does not automatically add an entry for it to the hash. That is if you have h = Hash.new(0)
and then you do p h[0]
, you'll print 0, but the value of h
will still be {}
(not {0 => 0}
) because the 0 is not added to the hash. If you do h[0] += 1
, this will call the []=
method on the hash and actually add an entry for 0 to it, so h
becomes {0 => 1}
.
So when you do @connections[1] << 2
in your code, you get the default array and perform <<
on it, but you don't store anything in @connections
, so it stays {}
. When you do @connections[i] = @connections[i].push(2)
or @connections[i] = (@connections[i] << 2)
, you're calling []=
, so the entry gets added to the hash.
However you should note that the hash will return a reference to the same array each time, so even if you do add the entry to the hash, it will likely still not behave as you expect once you add more than one entry (since all entries refer to the same array):
@connections = Hash.new []
@connections[1] = @connections[1].push(2)
@connections[2] = @connections[2].push(42)
puts @connections # => {1 => [2, 42], 2 => [2, 42]}
What you really want is a hash that returns a reference to a new array each time that a new key is accessed and that automatically adds an entry for the new array when that happens. To do that you can use the block form of Hash.new
like this:
@connections = Hash.new do |h, k|
h[k] = []
end
@connections[1].push(2)
@connections[2].push(42)
puts @connections # => {1 => [2], 2 => [42]}