Ruby Hash

The Hash class is widely used in Ruby code, due to its key/value structure. It has many interesting methods, aside from most basic ones, like #default and #key?, used to return a default value if the desired key was not found and verify if some key exists, respectively. There are accessor methods like #[], that return nil if the key doesn’t exist, and #fetch that you raise an error instead.

However, some methods like #fetch have different arity:

  • with 1 argument and a block, being the code evaluated inside the block the default value.
  • with 2 arguments, being the first one the key that you want to find the value, and the second a default value when that key doesn’t exist.

Example:

hash = { a: 1, b: 2 }

# Both forms will return the default value, as the key don't exists
hash.fetch(:c, 3) # => 3
hash.fetch(:c) { 3 } # => 3

Trickier #fetch Behaviour

As you saw both forms of calling #fetch have the same result but is the difference only of style and preference of each developer? No! There’s a subtle difference, that most times won’t make any difference in your application performance. But, let’s see an example to understand the impact of a wrong choice:

Imagine that you have an intensive operation to do if you don’t find a key in your Hash:

class MyClass
  self.my_intensive_computation
    sleep 5
  end
end

hash = { my_key: :ok }
hash.fetch(:my_key, MyClass.my_intensive_computation)
# after 5 seconds you'll get... => :ok

Oh, did you see what just happened?! Even with the key present in your hash, Ruby evaluated the default value, that is your intensive computation method!

Now if you use the block way:

hash = { my_key: :ok }
hash.fetch(:my_key) { MyClass.my_intensive_computation }
# instantly get... => :ok

Final Thoughts

Some methods in Ruby may receive a block as the last argument, and even return the same result when you pass a block to it. But some methods like Hash#fetch can have trickier behaviour when used with or without passing a block, that could have an important impact on your application.

Be aware of the different behavior of each form and write the code accordingly with your needs!

Did you already know about this behaviour of Hash#fetch?

Let me know if you liked this post! If you have any suggestions or critics, post a comment below!