A Hash in Ruby is a data structure that holds values in the key => value fashion. Symbols are often being used as keys to speed up the process of key lookup.

The Hash class provides many useful methods, some of them come from the Enumerable module. We won’t go through all of them now, we’ll rather focus on the often forgotten, but worth its value method: default().

Let’s start with the basics. Typical session with hash looks like this:

people = Hash.new

people["Mary"] = 78
people["John"] = 21
people["Frank"] = 52

puts "Name: John, age: #{people["John"]}."

The result is:

Name: John, age: 21.

We put some information concerning people’s names and age and then we display some of them. Given key (“John”) has been found and everything went smoothly. Let’s try to lookup for a non existing key:

people = Hash.new

people["Mary"] = 78
people["John"] = 21
people["Frank"] = 52

puts "Name: George, age: #{people["George"]}."
puts people["George"].inspect

The result now is:

Name: George, age: .
nil

The hash did precisely what we expected: it found nothing under the “George” key. Furthermore, it returned the nil value. What if we wanted to receive something different in such a situation? That’s where the default() method comes in.

standard_hash = Hash.new
puts standard_hash.default

our_hash = Hash.new
our_hash.default = 185
puts our_hash.default

The result should be:

nil
185

It seems we can set the default value returned by hash in case the key was not found. Let’s try this out with people and their age example:

people = Hash.new
people.default = 'unknown'

people["Mary"] = 78
people["John"] = 21
people["Frank"] = 52

puts "Name: John, age: #{people["John"]}."
puts "Name: George, age: #{people["George"]}."

Voila! Now our program works like if we expect the unexpected, and our users won’t get concerned if they ask for a person we don’t know anything about. By the way, instead of using the default() method, we can pass the default value to the Hash constructor:

people = Hash.new('unknown')
puts people["somebody"]

Then the “unknown” string should appear.

We should take into account that the default() method can be used in a more sophisticated way, e.g. to introduce the Null Object pattern in our program.

We often work with objects that are not being created locally. Instead, they are returned as a result of another method’s invocation. Sometimes the objects we receive are simply nil references. We have to check then if object really exists before invoking any of its methods, to avoid the NoMethodError being raised. Null Object pattern sets us free from having to check if received object is nil every time. Consider the following example:

class Introduce
  def initialize(name = '')
    @name = name
  end

  def introduce
    puts "Hello, my name is #{@name}!"
  end
end

class NullIntroduce < Introduce
  def introduce
  end
end

strangers = Hash.new
strangers.default = NullIntroduce.new

strangers["Holmes"] = Introduce.new('Sherlock Holmes')
strangers["Santa"] = Introduce.new('Santa Claus')

strangers["Holmes"].introduce
strangers["bvcxertg"].introduce
strangers["Santa"].introduce

We defined the Introduce class, which can be used to introduce strangers. We also created the NullIntroduce class, which does absolutely nothing when its object is asked to introduce itself. Then we put some data into the strangers hash and looked up for the existing and non existing key. The result is following:

Hello, my name is Sherlock Holmes!
Hello, my name is Santa Claus!

When we asked the “bvcxertg” person to introduce itself, nothing happened and this is how it was meant to be. In this simple way, we combined the Ruby hash default() method with the Null Object design pattern.

It seems that we exhausted the topic. Don’t forget about the default() method and use it wisely!

comments powered by Disqus