Michael Baird

Developer & UX Engineer

2 October 2014


The #fetch method in Ruby is implemented in both the Array and Hash classes, and offers very similar results to the #[] method.

options = { michael: 1, dwight: 2, jim: 3 }
options[:michael] # => 1
options.fetch(:michael) # => 1

The difference lies in how they handle missing keys:

options = { michael: 1, dwight: 2, jim: 3 }
options[:pam] # => nil
options.fetch(:pam) # => KeyError: key not found: :pam

Whilst the #[] method returns nil (usually, see footnote), #fetch will raise an exception. The method also accepts a second parameter or block, which is called only in the event of the key not being found. This could be used to raise a more informative error, or return an alternative value.

options = { michael: 1, dwight: 2, jim: 3 }
options.fetch(:pam) { |o| raise "Sorry, #{o} is not a valid option."} # => Sorry, pam is not a valid option.
options.fetch(:pam, 0) # => 0

Lastly, I’ve found #fetch useful for when a falsey value would be valid, and you need to distinguish between them and missing keys.

options = { }
logger = options[:logger] || Logger.new(STDOUT)
logger # => #<Logger:0x007ff5633a12f8...

options = { logger: false }
logger = options[:logger] || Logger.new(STDOUT)
logger # => #<Logger:0x007ff5633aa8a8...

To get around this, we can use #fetch to set the Logger if the key is not present.

options = { logger: false }
logger = options.fetch(:logger, Logger.new(STDOUT))
logger # => false

In the end, it comes down to whether or not you need nil or false to act the same as a missing key. If you don’t, use #fetch.

* When calling #[] with a missing key, the #default_proc is called if it is set, or the value of #default is returned (which by default, is nil). See Hash#default for more details.