Using “and” and “or” in Ruby

UPDATE: For a newer, better take on this topic, check out this post.

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_by_name(name) 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 an even simpler example:

foo = 42 && foo / 2

The intent here is to assign a variable and then divide it by 2. Since we are just assigning a constant value on the left side, both sides of the && will always be evaluated, right? 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.

Another way of thinking about and is as a reversed if statement modifier:

  next if widget = widgets.pop

becomes:

  widget = widgets.pop and next

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 = get_foo() or raise "Could not find foo!"

You can also look at or as a reversed unless statement modifier:

  raise "Not ready!" unless ready_to_rock?

becomes:

  ready_to_rock? or raise "Not ready!"

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.

UPDATE: Simplified and clarified some examples based on feedback; added comparisons to if/unless statement modifiers.

UPDATE 2: Preston Lee delivers a much more thorough history lesson on the Perl origins of these operators.

[ad#PostInline]