Robot Has No Heart

Xavier Shay blogs here

A robot that does not have a heart

Hash trumps case

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Two equivalent functions
def rgb(color)
  case color
    when :red   then 'ff0000'
    when :green then '00ff00'
    when :blue  then '0000ff'
    else             '000000' # Default to black
  end
end

def rgb2(color)
  {
    :red   => 'ff0000',
    :green => '00ff00',
    :blue  => '0000ff'
  }[color] || '000000'
end

Even though these functions are equivalent, the second carries more semantic weight – it maps a symbol directly to a color. The case sample makes no such guarantees since you can execute any arbitrary code in the then block. In addition, a hash is easier to work with – you can easily iterate over the keys, extract to another method if you need reuse, or query it for other properties (for example, 3 colors are available). It is also easier to read – both aesthetically and because it contains fewer tokens. In almost all circumstances I will prefer a hash over a case statement.

Relationships in data are easier to comprehend and manipulate than relationships in code.

  1. schlick says:

    Hey, that's a really great alternative to the case statement!

  2. schlick says:

    Although, case statements are actually quicker than the hash method above. So if performance is crucial then I'd recommend sticking to using case. Still, a really nifty alternative!

  3. Scott Fleckenstein says:

    "the second carries more semantic weight – it maps a symbol directly to a color. The case sample makes no such guarantees since you can execute any arbitrary code in the then block"

    No it doesn't -- the value could be any number of things besides a color and still not be an arbitrary code block. In either case, it would be programmer error to not have the available branches all map to a color value, but I've not seen any proof the possibility of that isn't appreciably lesser or greater with either method.

    "It is also easier to read – both aesthetically and because it contains fewer tokens."

    Yuck, no it isn't, unless it is an established pattern amongst you and your coders. The determiner of what branch to take is buried at the bottom of the block, meaning you've got to scan the whole thing before you can understand what is being switched upon. The case statement is familiar to even those unfamiliar with ruby.

    The cases you do mention ("iterate over the keys, extract to another method if you need reuse, or query it for other properties") certainly suggest using an object to satisfy those requirements, when they exist, but show me a programmer who has trouble reasoning about a simple case statement, and I'll show you a programmer who is (hopefully) still learning his trade.

    Using either method, I've seen overly complicated code, but the hash method starts out harder to understand because it doesn't convey a case statement as explicitly as... the case statement.

    Just IMO, of course.

  4. Dan Kubb says:

    I gotta agree with Scott. I find the case statement to be far easier to read.

    The Hash version is a bit obfuscated IMHO, with the usage of Hash#[] as the Hash is being defined. That's likely to trip up some ruby developers who've never seen that idiom before.

Post a comment


(lesstile enabled - surround code blocks with ---)

A pretty flower Another pretty flower