hash = {
:a => {:one => 1},
:b => {:two => 2}
}
I was wanting to write some code that would grab a value from a nested hash like the one above, without knowing whether any of the keys existed, or if even the hash existed. My immediate thought was just to use ifs:
def a1
if hash && hash[:a]
hash[:a][:one]
end
end
That’s a little gnarly with repetition though. So I thought maybe I could just use a rescue:
def a1
hash[:a][:one]
rescue
end
It certainly reads nicer, and explains the situation more clearly. But using exceptions like this smells a little dangerous. You don’t want to accidentally catch and ignore some other exception. But in this case, where the entire content of the method is just accessing hash values, it seems OK.
I wasn’t sure about performance though. So I wrote a little script to test the two strategies:
def rescuers
something = {:twelve => 12}
nothing = nil
something[:twelve]
nothing[:twelve]
rescue
end
def iffers
something = {:twelve => 12}
nothing = nil
if something
something[:twelve]
end
if nothing
nothing[:twelve]
end
end
start = Time.now
100000.times do
rescuers
end
puts "rescuers took #{(Time.now - start)} seconds"
start = Time.now
100000.times do
iffers
end
puts "iffers took #{(Time.now - start)} seconds"
Of course, this is hardly a “natural” benchmark. But it’s better than nothing.
It turns out, on my machine, the rescue strategy is about a factor of 10 slower than the conditional. That’s pretty damning, HOWEVER, you can still do 100,000 rescues in a second. So, unless I’m doing this thousands of time in a web request, it won’t really tip any important scales.
I’m going to go with the rescue for now, and see how I feel about it.