Siaris
Simple Things
Syndicate: full/short
Siaris
Categories
General0
News2
Programming2
LanguageBits0
Perl50
Ruby10
VersionControl1
Misc0
Article Calendar
<= April, 2014
S M T W T F S
12345
6789101112
13141516171819
20212223242526
27282930
Search this blog

Key links
External Blogs
Brought to you by ...
Ruby
1and1.com

Hash with block or Block with hash?

Andrew L. Johnson

Not exactly new, passing blocks to Hash.new has been around for a while (since the 1.8.0 release I think). This can be used to supply a default value or action for accessing keys not in the hash.

  hash = Hash.new {|h,k| h[k] = "Default Value"}

  hash = Hash.new {|h,k| raise "No Such Key #{k}"}

Note, the objects yielded to the block are the hash and the key (not a key and a value, which is an easy but nonsensical mistake to make).

In the first example above we didn’t just return a default value, we also assigned to the appropriate key in the hash — next time we try to access the hash using this key we will get the default value directly instead of having to evaluate the block again. This point of view — a hash with a block attached to generate default values — is useful, but not terribly interesting.

Turning the view around we have a block with an attached cache — giving us simple memoization. Here’s a little memoized factorial calculator:

  fact = Hash.new {|h, n| n < 2 ? h[n] = 1 : h[n] = h[n-1] * n}
  p fact[4]   #--> 24
  p fact      #--> {1=>1, 2=>2, 3=>6, 4=>24}

Now, there are obvious limitations: the [] hash method takes a single object as a key so you can’t pass multiple parameters directly (you’d need to wrap them in an array or something), and, parameter caching will be based on the #hash method of the objects used as keys. Another limitation is cache size and expiry — in which case you might want to try the memoize module available on the RAA.