How does shovel (<<) operator work in Ruby Hashes?
You have mixed up the way this works a bit. First off, a Hash doesn't have a <<
method, that method in your example exists on the array.
The reason your code is not erroring is because you are passing a default value to your hash via the constructor. http://ruby-doc.org/core-1.9.3/Hash.html#method-c-new
hash = Hash.new([])
This means that if a key does not exist, then it will return an array. If you run the following code:
hash = {}
hash[:one] << "uno"
Then you will get an undefined method error.
So in your example, what is actually happening is:
hash = Hash.new([])
hash[:one] << "uno" #hash[:one] does not exist so return an array and push "uno"
hash[:two] << "dos" #hash[:two] does not exist, so return the array ["uno"] and push "dos"
The reason it does not return an array with one element each time as you may expect, is because it stores a reference to the value that you pass through to the constructor. Meaning that each time an element is pushed, it modifies the initial array.
When you're doing hash = Hash.new([])
you are creating a Hash whose default value is the exact same Array instance for all keys. So whenever you are accessing a key that doesn't exist, you get back the very same Array.
h = Hash.new([])
h[:foo].object_id # => 12215540
h[:bar].object_id # => 12215540
If you want one array per key, you have to use the block syntax of Hash.new
:
h = Hash.new { |h, k| h[k] = [] }
h[:foo].object_id # => 7791280
h[:bar].object_id # => 7790760
Edit: Also see what Gazler has to say with regard to the #<<
method and on what object you are actually calling it.