Using “and” and “or” in Ruby

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

andIs 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]

Creative Commons License
This work, unless otherwise expressly stated, is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License.

Related posts:

  1. “and” and “or” are like backwards statement modifiers
  2. The Procedure/Function Block Convention in Ruby
  3. Calling Grandparents in Ruby
  4. First and Rest in Ruby
  5. Your code is broken, and Ruby can help you fix it
This entry was posted in Uncategorized and tagged , . Bookmark the permalink.
  • Yule

    Very well explained.
    The “or” and “and” operators are very much under-used in ruby to maximize their actual use.
    There is a time to use and, and a time to use or and A time to use && and a time to use ||.
    Or should that be
    There is a time to use and, && a time to use or && A time to use && && a time to use ||.
    Read and as part of a sentence, rather than a modifier to it, the difference becomes clear.

  • chris

    Very interesting. Up until now I've always used the boolean operators to control flow. I will have to give this a try as I see how the lower operator precedence is a benefit in linking operations together.

  • Chrisr

    Thanks, I always wondered the difference

  • seydar

    Thank you. I had always assumed that 'and' and 'or' were NOT short-circuiting.

  • Jason the Saj

    And if you're looking for code readability, check out ColdFusion.

    LOL

  • Jason May

    Yes! I actually recently started using these idioms. I think it only makes sense some of the time. For instance, I've seen people do something along the lines of

    “Condition?” and/or do_something

    whereas it makes more sense when it's

    “Perform some sort of action” and/or do_something

    I used this exact reasoning to argue against people who think the operator precedence between 'and' and '&&' is a nuisance. Great post!

  • Jon Atack

    Thanks, Avdi, that was a good reminder.

  • Xavier Noria

    The example with Post.find wouldn't work because an exception is raised if the post is not found. You could for example change it with Post.find_by_slug(params[:slug]), which would return nil if not found.

  • Nothanks

    I've not used Ruby. So you are saying that if it raises an exception, the “and” part will be executed? That's bad design in my opinion. An exception should count as “false”

  • Andrius Chamentauskas

    I always use 'and' and 'or' instead of '&&' and '||' in my conditions. The reason for this is that i can quick assign variables in conditions without using brackets. Compare:
    if a = b.c and a == 1
    to:
    if (a = b.c) && a == 1
    Really the only reason to use && or || is for those a ||= 1, a = b || c cases.

  • chastell

    My favourite use of ‘or’ is to chain subsequent Numeric#nonzero? calls in spaceship operator definitions; this short-circuits the sequence of calls to bail out on the first difference between self and other, which means you simply put the checks in order of decreasing importance:

    def <=> other
    (foo <=> other.foo).nonzero? or (bar <=> other.bar).nonzero? or (qux <=> other.qux).nonzero? or quux <=> other.quux
    end

  • Nothing

    Very interesting. As a newbie Ruby user I can see this being useful. Thanks :D

  • http://wideteams.com Avdi Grimm

    No, this has nothing to do with exceptions. Exceptions will terminate execution normally. “and” will only execute the clause on the right-hand side if the clause on the left-hand side returns a “truthy” value.

  • http://wideteams.com Avdi Grimm

    Personally I think that's one too many activities in the condition part of an “if” statement. I don't mind a single assignment to capture the condition result (if match_data = s.match(/foo/) then …). Beyond that it should really be done outside the condition, IMO.

  • http://wideteams.com Avdi Grimm

    It's weird, I use the method name .find() and everyone assumes I'm talking about ActiveRecord. Silly Rails people ;-)

    But I may change it to avoid similar confusion in future. Thanks!

  • http://wideteams.com Avdi Grimm

    :-)

  • http://wideteams.com Avdi Grimm

    Yeah, the first example usually reads better as:

    do_something if/unless condition?

    Glad you liked it!

  • http://wideteams.com Avdi Grimm

    :-P

  • http://wideteams.com Avdi Grimm

    Yeah, I've run into that misconception before. Glad to be able to clear that up.

  • http://wideteams.com Avdi Grimm

    You're welcome!

  • http://wideteams.com Avdi Grimm

    Good luck!

  • http://wideteams.com Avdi Grimm

    Indeed :-) Thanks for the comment.

  • http://wideteams.com Avdi Grimm

    Very nice, I will keep that idiom in mind. Thanks!

  • http://wideteams.com Avdi Grimm

    You are quite welcome, and good luck learning Ruby!

  • http://remi.org remi

    I use 'and' and 'or' in my Ruby all over the place. I do not typically use them for control flow; I use them as boolean operators.

    draw :cartoons if @chunky == 'bacon' and @fox.height == :tall

    I use 'and' exactly like I would use && and I use 'or' exactly like I use would ||. So long as my specs pass, I don't see any problem! I'll keep this article in mind if I ever run into issues, but using and/or like &&/|| hasn't hurt me for the past few years. In fact, it's my company's policy!

  • http://remi.org remi

    I have to agree. Typically, I consider assignment in a conditional to be a code smell. It's very often a mistake where someone meant to check for equality and, otherwise, it's often unclear. That's not to say that I never do it, but you should be careful when you do!

    if user = User.find_by_name('admin')
    # do some stuff because we found a user!
    end

    ^ I don't mind that, but I can't imagine adding more conditions and keeping it clear

  • http://remi.org remi

    I use #detect and #select to avoid that confusion. Also, if you *are* using ActiveRecord, trying to use #find can bite you because AR overrides it on associations.

  • http://thedailyt.com Terje

    Thanks for helping me make sense of why and/or have a different precedence from &&/||. I wrote about this a while back regarding PHP: http://thedailyt.com/2008/04/php-operator-oopsies/ and didn't at the time see the usefulness of it.

  • Garrett

    'and' and 'or' do not operate like && and || in assignment statements. For example:

    >> condition = true && false
    >> condition
    => false

    >> condition = true and false
    >> condition
    => true

    It also plays hell with the ternary operator.

  • Ste

    There's a cleaner alternative to this scenario (assuming you don't need an “else” block):

    user = User.find_by_name('admin') and begin
    # do some stuff because we found a user!
    end

    This way you save yourself one level of indentation if you have to handle exceptions inside the block

  • Xavier Noria

    @remi, yeah that's needed for associations if you want Enumerable#find, but models are not enumerables in AR. AR::Base.find is unrelated to Enumerable#find, so there can't be confusion in Post if it is an AR model

    @Avdi what did you have in mind in that example? Where do you use that idiom?

  • http://techarch.pip.verisignlabs.com/ Philippe Monnet

    Avdi, thanks for the nice, brief and clear post on this topic!

  • http://twitter.com/saturnflyer Saturn Flyer

    Thanks for writing this. It's been on my list of things to dig into but you've done it for me.

  • Mindtonic

    ^ Nice example of another use of 'and'

  • http://www.creative-wrks.com/ Robert

    The exception wouldn't count as true, but would short circuit the logic chain to the ensure/rescue parts of the block (if present). So if nothing was found in the original example the second part of the and would not execute. If altered like Xavier mentioned, it the post would only be published if found. (Essentially they work the same for this example, but through completely different routes of logic.)

    To summarize: no, Ruby doesn't work that way.

  • http://www.kuhnsfam.com metavida

    I guess technically you could do something like this if you wanted an “else” block. Though it's probably simpler to use an if-else rather than remembering to always return true at the end of your “and” block. If you forget that crucial step, or a future developer doesn't realize it, you'll end up never reaching the “or” block.

    user = User.find_by_login('reynardmh') and begin
      # do some stuff, because we found a user!
      true
    end or begin
      # do other stuff, because we didn't find a user!
    end

  • http://wideteams.com Avdi Grimm

    This will eventually bite you, and it will confuse the heck out of any coders you add to your team, who are most likely to have learned (correctly, IMO) to do the exact opposite. I can't fault you for preferring “and”./”or” as a personal style. But frankly that's a classic example of something that should never be made into policy.

  • http://wideteams.com Avdi Grimm

    You're welcome!

  • http://wideteams.com Avdi Grimm

    No problem ;-)

  • http://wideteams.com Avdi Grimm

    Glad I could help!

  • http://wideteams.com Avdi Grimm

    I had in mind a generid .find() method. No specific framework was implied. I've since updated it to be more ActiveRecord-friendly.

  • http://remi.org remi

    We find that 'and' and 'or' make the code more readable and clear.

    The most important thing, IMHO, is that your test suite passes. Knowing about the slight differences is very important as a Ruby programmer, just like knowing the difference between using lambda and Proc.new.

    Testing is what keeps these things from biting you.

  • http://remi.org remi

    These are great examples of how to use and/or for flow control but the code is pretty horrendous, IMHO :/ As you said, an if-else would be easier to understand in this scenario … I understand that you're merely demonstrating and/or/begin.

    Remember … cleverness for the sake of cleverness is evil in code! Atleast in a real project. Screwing around after hours is the perfect time to write clever code :P

  • http://wideteams.com Avdi Grimm

    I find that in large, time-critical projects, it's not enough that the test suite passes. It's also important that when it fails, it fails in readily understandable ways as often as possible. As in “Oh, I've seen that error signature before, I know what to do”. This is the value of sticking with community conventions: a new developer doesn't have to spend weeks tearing her hair out because whenever she tries to add a feature the code breaks in subtle ways that she's not familiar with. Like, say, precedence issues caused by using a control flow operator where a boolean op belongs ;-)

  • http://wideteams.com Avdi Grimm

    And let me just say that for a long time I did as you did: preferring “and” and “or” for their readability, just as I had done in C++ (where they really ARE equivalent, although few know that they even exist…). I changed my practice because I was writing code that was a) harder for others in the community to understand; and b) prone to weird interactions with e.g. the unless/else modifiers.

  • http://mattbeedle.com Mattbeedle

    Thanks, great post, you really cleared this up for me!

  • Alpha

    You can make this article clearer by writing one in the form of the other:

    foo = 42 && foo / 2 # (foo = 42) and (foo / 2)
    foo = 42 and foo / 2 # foo = (42 && foo) / 2

  • http://www.kuhnsfam.com metavida

    I absolutely agree, remi! I can't see myself ever using that demonstration code in a real product :-)

  • eydaimon

    the precedence of these are pretty much the same as in any other interpreted language which bumps the english versions down. Nothing really new here, no?

  • http://twitter.com/andrewjgrimm Andrew Grimm

    Is this why there's no plain English version of exclusive or? http://stackoverflow.com/questions/585195/keywo…

  • http://wideteams.com Avdi Grimm

    I think that's a safe bet, yes.

  • http://wideteams.com Avdi Grimm

    Knowing a feature exists and knowing how to use it are two different things.

    Apart from Perl and Ruby, what other interpreted languages have this feature?

  • eydaimon

    PHP, mysql … I'm guessing any language which offers both notations will have the lower precedence for the english version.

  • Matthew Willson

    This is another idiom which I've grown slightly fond of (yet haven't seen that much in wider use):

    variable = expression() and begin
    do_stuff_with(variable)
    end

    as opposed to this, which triggers warnings about == vs = ambiguity:

    if (variable = expression())
    do_stuff_with(variable)
    end

    or this, which is just a bit verbose for the compulsive syntax optimiser:

    variable = expression()
    if variable
    do_stuff_with(variable)
    end

  • http://www.prestonlee.com/2010/08/04/ruby-on-the-perl-origins-of-and-versus-and-and-or/ Preston Lee

    Avdi: In response to the Perl side, I've put up a few quick notes in response. Thanks and keep up the good work. :) -Preston

    http://www.prestonlee.com/2010/08/04/ruby-on-th…

  • Exolon

    I think you got them the wrong way around.

  • Rohit

    Thanks Advi,
    The article was very helpful. This idiom goes to my note-book right now, so that whenever I read it I come to know about it.

  • zipizap

    Very good explanation!

  • mattonrails

    I never realized how wrong I had it until I read this post. Thank you! :)

  • http://wideteams.com Avdi Grimm

    Glad it helped!

  • Phil

    in your example
    foo = (42 && foo) / 2  should be foo = 42 && (foo / 2 )

    using http://www.techotopia.com/index.php/Ruby_Operator_Precedence

  • Anonymous

    this article is missing very important bit:

    “&&” has higher precedence than “||” like in most other mainstream languages;

    but “or” and “and” in ruby have the same(!) precedence level!

    so if you write

    (func1 || func2 && func3), it’s (func1 || (func2 && func3))

    but

    (func1 or func2 and func3) is interpreted as ((func1 or func2) and func3)

    because of shorcircuiting, if func1 is true, both func2 and func3 won’t be called at all in the first example

    but in the second example func3 WILL be called!

    this difference is subtile enough that I really do not recommend newbies to use “and” and “or” in ruby at all.

  • Anonymous

    as I said in another comment here, there’s a difference.

    ruby is the only language i know, which places “and” and “or” on the SAME precedence level. unlike perl and php and many others. this could bite you.

  • Anonymous

    So what *is* the difference between perl and ruby? My experience has been that perl and ruby treat them the same.

    Note that perl initializes variables to 0, not nil as in ruby, so hence the foo=0 in the ruby version. 

    $ ruby -e ‘foo=0; foo = 42 && foo / 2; print foo’  #=> 0

    $ ruby -e ‘foo=0; foo = 42 and foo / 2; print foo’ #=> 42

    $ perl -e ‘$foo = 42 && $foo / 2; print $foo’        #=> 0

    $ perl -e ‘$foo = 42 and $foo / 2; print $foo’      #=> 42

    They appear to to be the same.

  • Anonymous

    actually, perl “initializes” variables to “undef” which is direct equivalent of ruby “nil”, but autoconverts undef to 0 in numeric expressions without warnings.

    difference between perl and ruby “and” and “or” is seen when you use both and and or in the same expression.

    ~> perl -e ’1 || 0 && die(“oh”)’

    ~> ruby -e ‘true || false && fail(“oh”)’

    ~> perl -e ’1 or 0 and die “oh”‘

    ~> ruby -e ‘true or false and fail “oh”‘

    -e:1: oh (RuntimeError)