23 Mar 2009

Use Has.new to set a default value

Very early while learning Ruby I came to know of the fact that while creating a hash you can supply default value.

>> h = Hash.new('foo')
=> {}
>> h['1'] = 100
=> 100
>> h['1']
=> 100
>> h['2']
=> "foo"

As you can see for the key ‘2’ you got the value ‘foo’ which was the default value.

Where to put this technique in use

I knew this behavior of Hash but I never used it myself until now. Now I have started seeing why it is such a powerful tool.

In order to understand the usefulness of this technique take a look at this piece of code from Rails.

# lib/action_controller/rescue.rb

DEFAULT_RESCUE_RESPONSE = :internal_server_error
DEFAULT_RESCUE_RESPONSES = {
  'ActionController::RoutingError'             => :not_found,
  'ActionController::UnknownAction'            => :not_found,
  'ActiveRecord::RecordNotFound'               => :not_found,
  'ActiveRecord::StaleObjectError'             => :conflict,
  'ActiveRecord::RecordInvalid'                => :unprocessable_entity,
  'ActiveRecord::RecordNotSaved'               => :unprocessable_entity,
  'ActionController::MethodNotAllowed'         => :method_not_allowed,
  'ActionController::NotImplemented'           => :not_implemented,
  'ActionController::InvalidAuthenticityToken' => :unprocessable_entity
}

base.rescue_responses = Hash.new(DEFAULT_RESCUE_RESPONSE)
base.rescue_responses.update DEFAULT_RESCUE_RESPONSES

In the above case the final goal is to create a hash rescue_responses . The requirement is that if a key is not found then use the default value. Without the power of the creating a hash with default value you would probably write like this

if base.rescue_responses.has_key(key)
 ...
else
 return DEFAULT_RESCUE_RESPONSE
end

What it means is that every single time that hash is used then that check has to be done. Also it limits your ability to send the hash around. You cannot send this hash around freely because someone might just look for the key and might not check return the default value incase the key is missing.

In this case Hash was created with a default value. Now that hash has a default value you can send this hash anywhere fearlessly. I guess using this technique of creating hash with default value would classify as ruby idiomatic way and ,probably, I did not use this feature because prior programming languages like Java did not allow me to do that.