One of the popular feature’s of Ruby’s Hash object is that you can specify a default value for entries in the hash. For example, a common use case is to count the frequency of objects in an array.
Using the Hash initializer we can specify the default value for the hash as 0, which simplifies our code:
Another common use case is to have every entry in the hash be an array. As an example I’m grouping colours by their starting letter.
We can use the same trick as above to specify an empty array as the default value for the hash, with dire consequences:
This is obviously not what we wanted. Ruby is indeed setting the default value for the hash to an array, but it’s using the same array everywhere. So every modification we make will modify this one, original array.
Ruby also allows us to specify a block as the initializer, which will be called if the key does not already exist in the array.
Here is the relevant documentation for Hash#new:
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.