The Elements of Style in Ruby #7: The case against ===
Today we’ll discuss the following section from the Ruby Style Guide:
Avoid explicit use of the case equality operator
===. As it name
implies it’s meant to be used implicitly by
outside of them it yields some pretty confusing code.
For those of you who don’t know of the case equality operator
it’s the magic behind
case that allows us to write code like this:
case something when Array then ... when 1..100 then ... when /some_regexp/ then ... end
Ruby will convert the above code to something like:
case something when Array === something then ... when 1..100 === something then ... when /some_regexp/ === something then... end
For many classes (like
=== will behave the
same way as
==. On the other hand -
define customized versions of the operator method
===. Knowing how
these 3 classes have defined
===, the case expression is also
equivalent to this one:
case something when something.is_a? Array then ... when 1..100.include? something then ... when something =~ /some_regexp/ then ... end
So far everything is peachy, right?
The problem with the
=== is that when some people see it they decide
it’s very cool and start using it all over their code instead of
its much clearer alternatives. I’ve seen
=== (ab)used quite often for instance of checks.
# wtf, why doesn't this work??? # extremely common mistake I've seen numerous times return unless a === Array # === is defined in Module return unless Array === a # same as Array.===(a)
I’ve also seen it used many times for range inclusion
tests. Fortunately nobody has decided so far that
=== is preferable
=~ for regular expressions.
It should be our utmost goal as programmers to produce clear and easily digestible code. This means we should abstain ourselves from doing clever tricks like:
Array === something (1..100) === 7 /something/ === some_string
And bet on clarity instead:
something.is_a?(Array) (1..100).include?(7) some_string =~ /something/
They don’t call it the case equality operator for no reason - it’s
meant to be used internally by
case expressions. I guess if it were
a regular method (instead of an operator method) we’d never have had
to deal with its abuse.
As usual I’m looking forward to hearing your thoughts here and on Twitter!
Code long and prosper!