Good Ruby Idiom: and/or operators
Any tutorial and book will teach you there are two sets of similar
operators in Ruby: &&
/||
vs and
/or
(and also &
/|
for bit
operations, but that’s not the case today). But typical tutorial will not
provide further explanation why we need both of those pairs.
Some of tutorials and blog posts about this matter even go as far as
explicit recommendations never use and
/or
, because &&
and ||
is enough for all reasonable cases, and because and
/or
provide only
confusion. They would typically warn
you about and
’s lower precedence than =
, but nobody will tell you
how this can and should be useful.
Unfortunately, even respectable (and forced by Rubocop)
Ruby Style Guide explicitly
bans those
operators and embraces usage of &&
and ||
even for control flow.
(Faithfully, this is one of Rubocop checks I turn off immediately after
adding Rubocop to every new project of mine.)
But and
and or
are you friends, which allow to write very clean and
DRY and readable code: exactly the thing we love Ruby for.
They are control flow operators.
Example:
This idiom is one of (numerous) good parts of Perl heritage in Ruby, it is very terse and readable and demonstrate intentions well.
Somebody may argue &&
and ||
can be used for both examples? Or, to
heck with it, why we should do control flow this way, we have our if
and unless
, even modyfying ones?..
So, let’s look at some examples.
Case 1. Task: receive some data from method; if data received, process it further, if not—return (or fail) immediately. For example, complex Nokogiri document parsing:
What options do we have?
Which is cleaner declaration of intent?.. For me—definitely the last one.
And you can’t replace it with ||
, exactly because of operator precedence.
Case 2. List of checks: before some complex processing you want to check your arguments and maybe state, fail if something is not OK, and only then do the processing.
I do it like this:
The same code with modyfying if/unless is not that clear:
Code with control flow operators reads like
IMPORTANT_CONDITION or raise ...something...
. Code with modifying statements
reads like raise THIS LONG VALUEABLE STRING unless .... something
.
And again, you will not want to use &&
and ||
here because of operator
precedence (and some complications with parentheses, also).
I like this (a bit abstruse) definition:
Logical operators (
&&
and||
) operate on values; control flow operators (and
andor
) operate on side effects.
PS: Of course, this is not first blog post with such kind of rant/explanation, there are plenty of them. Just wanted to make [another] clear point about that.