HashRefs as lookup tables in Perl

2013-07-14

One of my favourite memes in Perl is using anonymous HashRefs for lookup tables. I use this whenever I have some value that depends on a key, like the name for a mode or something:

my $title = {
    main     => 'Main View',
    overview => 'Overview',
    latest   => 'Latest Values',
}->{$mode} || 'Untitled';

This replaces an if-then-else chain in other languages (though many will have a more concise syntax than this, for example switch statements):

var title;
if (mode == 'main') {
    title = 'Main View';
} else if (mode == 'overview') {
    title = 'Overview';
} else if (mode == 'latest') {
    title = 'Latest Values';
} else {
    title = 'Untitled';
}

Quite a lot of this syntax is boilerplate, making this harder to read. A more important difference, in my opinion, is that the if-then-else and switch constructs are statements, not expressions, so you can't use them in other statements, like you can with HashRef lookups:

calculate( 
    4, 
    {
        main     => 1,
        overview => 2,
    }->{$mode} || 0, 
    18,
);

There's another method which is an expression, a 'truth table' of ternary operators:

my $title = ($mode eq 'main'    ) ? 'Main View'     :
            ($mode eq 'overview') ? 'Overview'      :
            ($mode eq 'latest'  ) ? 'Latest Values' : 
                                    'Untitled'      ;

This requires an explicit comparison operation, though, so its strengths lie elsewhere. Also, it might be a bit harder to read when you're not familiar with it. And pretty-printing may actually destroy the legibility, wheras for HashRefs, the default indentation would be correct.

As a bonus, with the HashRef method, you get two places for defaults: a default key and a default value.

my $category = {
    main    => 'cat_start',
    archive => 'cat_archives',
}->{$mode || 'main'} || 'cat_other';