As a follow up to my first post I’d like to quickly run over the “default value” related features of Ruby’s Hash and explain when to use them.
totals = Hash.new(0)
totals[:jeff] # => 0
totals[:ann] += 1 # => 1Use this when:
Do not use this when:
scored = Hash.new([])
scored[:jeff] # => []
scored[:ann] << 'A+'
scored[:jeff] # => ['A+']
scored # => {}💩
fizz_bang = Hash.new { |hash, key| hash[key] = fizz_and_or_bang(key) }
fizz_bang[3] # => 'Fizz'
fizz_bang[5] # => 'Bang'Use this when:
Don’t user this when:
It’s possible to change the default_proc and default value. The last assignment will be what’s used.
h = Hash.new
h[:jeff] # => nil
h.default = 'default'
h[:jeff] # => 'default'
h.default_proc = -> (*) { 'default_proc' }
h[:jeff] # => 'default_proc'
h.default = nil
h[:jeff] # => nil
h # => {}New Ruby programmers probably do something like this:
hash = {}
hash[:key] ||= 1This works fine until some falsy values are introduced:
hash = {1 => nil, 2 => false}
hash[1] ||= 1
hash[2] ||= 2
hash # {1 => 1, 2 => 2}😩
When using || your falsy values will be overwritten. This is most probably not your intention. Instead of that use Hash#fetch.
hash = {1 => nil, 2 => false}
hash.fetch(1) { 1 }
hash.fetch(2) { 2 }
hash # {1 => nil, 2 => false}Hash#fetch is best used when:
It’s also great to ensure a key is present
Hash.new.fetch(:a_missing_key)
# KeyError: key not found: :a_missing_keyDon’t use it when:
Hash#fetch also has a second notation for the default value:
Hash.new.fetch(:a_missing_key, 'default value') # => 'default value'I only use the notation with a block. There are no real benefits to the other notation except maybe some performance difference in super simple cases. In most cases though, the block version will be the better choice. It will postpone the evaluation of the default value until it’s needed; and - at lest to me - it looks better. 😍
So, what do you think this will do?
Hash.new('default value') { |hash, key| hash[key] = key.to_s }How about this?
Hash.new.fetch('default value') { 'value' }👉 Try it yourself 👈, I found it very surprising 😃