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 bycase
expressions and
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 Fixnum
and String
) ===
will behave the
same way as ==
. On the other hand - Module
, Range
and Regexp
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
to =~
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!