RUBY / CHAPTER 07
Hash defaults and mutation
IntermediateMake shared state and missing-key behavior explicit.
By the end of this chapter
- Create independent collection defaults per key
- Distinguish missing keys from nil values
- Track shallow copies and mutation conventions
The idea
A hash associates keys with values and preserves insertion order. Reading an absent key normally returns nil, which may be indistinguishable from a deliberately stored nil unless you use key? or fetch. Fetch is useful when a missing entry is a contract violation or needs an explicit fallback. Symbol and string keys are distinct, so normalize external keys only according to a documented policy.
Hash.new([]) supplies the same default array on every missing lookup; it does not store a separate array for each key. Use a default block that assigns a fresh array to the requested key when building groups. Assignment and shallow duplication can also preserve references to nested objects. Mutation should be intentional and documented; a bang in a method name is a convention, not a universal guarantee.
groups = Hash.new { |hash, key| hash[key] = [] }
groups[:open] << 1
groups[:closed] << 2
p groups[:open]
p groups[:closed][1] [2]
The default block runs for each missing key and stores a new array, so adding a closed item does not change the open group.
Try it yourself
Count occurrences of strings using a hash whose missing count starts at zero.
Use your own editor for this exercise. Runnable challenges on CodeQuest are available for JavaScript, Python, and SQL.
CHECK YOUR UNDERSTANDING