RUBY / CHAPTER 07

Hash defaults and mutation

Intermediate

Make 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.

Ruby example
groups = Hash.new { |hash, key| hash[key] = [] }
groups[:open] << 1
groups[:closed] << 2
p groups[:open]
p groups[:closed]
Result
[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

Chapter checkpoint

Which definition creates and stores a separate array for each missing key?