Take the 2-minute tour ×

I was going through Ruby Koans tutorial series, when I came upon this in about_hashes.rb:

def test_default_value_is_the_same_object
  hash = Hash.new([])

  hash[:one] << "uno"
  hash[:two] << "dos"



The values in assert_equals, is actually what the tutorial expected. But I couldn't understand how there is a difference between using << operator and = operator?

My expectation was that:

  • hash[:one] would be ["uno"]
  • hash[:two] would be ["dos"]
  • hash[:three] would be []

Can someone please explain why my expectation was wrong?

share|improve this question
Funny, that's exactly what I expected. Then, mountains were again merely mountains. –  Christopher Perry Mar 3 '13 at 7:19

2 Answers 2

up vote 35 down vote accepted

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[: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.

share|improve this answer
+1 for using object_id to show the reference. –  Gazler Feb 18 '12 at 18:09
Got it thanks. So, the original empty array is an object that is stored as a default value. And we keep getting back that original object instead of a nil. Neat! Thanks to both answers (by you and @Gazler), upvoting both, but accepting this. –  bits Feb 18 '12 at 18:12

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.

share|improve this answer
Thanks @gazler. This helped to make it clear. –  bits Feb 18 '12 at 18:15
Thank you much sir –  Etch Dec 5 '12 at 22:18
This should be the accepted answer. Much more clear explanation. Thanks –  chopper draw lion4 Nov 30 at 1:18

Your Answer


