If you use Ruby long enough, you will discover the and
and or
operators. These appear at first glance to be synonyms for &&
and ||
. You will then be tempted to use these English oprators in place of &&
and ||
, for the sake of improved readability.
Assuming you yield to that temptation, you will eventually find yourself rudely surprised that and
and or
don’t behave quite like their symbolic kin. Specifically, they have a much lower precedence. At this point, you may decide to swear off the use of and
and or
as too confusing.
But that would be doing your code a disservice. and
and or
are useful operators; you just need to understand their special place in Ruby programs.
and
and or
originate (like so much of Ruby) in Perl. In Perl, they were largely used to modify control flow, similar to the if
and unless
statement modifiers. A common Perl idiom is:
do_something() or die "It didn't work!";
The and
and or
keywords serve the same purpose in Ruby. Properly understood, and
and or
are control flow operators, not boolean operators.
and
and
Is useful for chaining related operations together until one of them returns nil
or false
. For instance:
post = Post.find(id) and post.publish!
Here, the post will only be published if it is found, due to the short-circuiting nature of and
. How does this differ from &&
? Let’s take a look at a simple example:
foo = 42 && foo / 2
What will we get when we evaluate this code? Let’s give it a try:
NoMethodError: undefined method `/' for nil:NilClass from (irb):18 from :0
Was that what you expected? As it turns out, with the relatively high operator precedence of &&
, the way that code is actually parsed looks like this:
foo = (42 && foo) / 2
…which is clearly not what we want. Contrast that to the and
version:
foo = 42 and foo / 2 => 21
…and now we have the answer we were expecting.
or
or
, likewise, is useful for chaining expressions together. The best way to think about the chains constructed with or
is as series of fallbacks: try this, if that fails try this, and so on. For instance:
foo = cach[:foo] or foo = get_foo() or raise "Could not find foo!"
Conclusion
and
and or
, despite an apparent similarity to &&
and ||
, have very different roles. and
and or
are control-flow modifiers like if
and unless
. When used in this capacity their low precedence is a virtue rather than an annoyance.
Thanks to: Avdi Grimm.
http://avdi.org/devblog/2010/08/02/using-and-and-or-in-ruby/
Related Articles
- Using “and” and “or” in Ruby (avdi.org)
- Ruby Books (oscardelben.com)