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.
July 03, 2008 at 7:58 PM
Hey, that's a really great alternative to the case statement!
July 05, 2008 at 8:30 PM
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!
August 27, 2008 at 5:03 PM
"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.
March 05, 2009 at 2:08 PM
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.