Ruby language design is based on the principle of least surprise. Don’t quote Matz on this line, it was not him actually who brought this up. But, true, Ruby is supposed to reduce your frustration while developing.
I was actually surprised yesterday that I encountered a frustrating situation.
Look at the following code:
hn = Hash.new(0) hn['key'] += 1 puts hn['key'] # you expect 1 and it works puts ha = Hash.new([]) ha['1'] << '1' ha['2'] << '2' puts ha['1'] # you expect 1, but you get 1, 2 puts puts ha['3'] # you expect nil, but the output is 1, 2
Why is this? How come, specifying an array as default value for a hash is not doing the right thing? The documentation tells, that the same single object is used to initialize the hash values, in case the hash key does not exist. So, the initial value for all hash keys becomes the same single array object. I bet that reading the source code only, most programmers assume that a new Array object gets instantiated for every new hash key.
Let’s fix it!
We need to use the default_proc method on the hash.
ha = Hash.new
ha.default_proc = lambda {|hash, key| hash[key] = []}
ha['1'] << '1'
ha['2'] << '2'
puts ha['1']
# you expect 1 and it works
puts
puts ha['3']
# you expect nil and it works
Ruby is awesome, but not always follows principle of least surprise. Now I understand why Matz did not say it himself
on August 29th, 2009 by admin