Using “and” and “or” in Ruby

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

UPDATE 2: This topic is part of the Graceful.Dev Flawless Ruby course, which is now completely free!

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: Preston Lee delivers a much more thorough history lesson on the Perl origins of these operators.

UPDATE 2: This topic is part of the Graceful.Dev Flawless Ruby course, which is now completely free!

81 comments

  1. 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.

  2. 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.

  3. 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!

  4. 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.

    1. 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”

      1. 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.

      2. 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.

    2. 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!

      1. 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.

        1. @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?

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

  5. 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.

    1. 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.

      1. 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

        1. 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

          1. 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<br>  # do some stuff, because we found a user!<br>  true<br>end or begin<br>  # do other stuff, because we didn't find a user!<br>end

          2. 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 😛

  6. 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

  7. 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!

    1. '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.

    2. 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.

      1. 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.

        1. 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 😉

        2. 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.

      2. I know this is really old, but can you explain when using “if @chunky == ‘bacon’ and @fox.height == :tall” will bite you?

        1. Because someday someone will change one side of that ‘and’ to an expression which (to their surprise) doesn’t play well with its precedence, and they will spend a long time trying to understand why the apparently obvious logic isn’t working right.

  8. 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

  9. 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?

    1. 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?

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

    2. 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.

      1. 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.

        1. 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)

  10. 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

  11. 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.

    1. You are correct, but the point was to illustrate that foo will not be assigned before the division occurs and that regardless of whether ‘&&’ has precedence over ‘/’ or not (thereby causing the parentheses to be placed one way or the other as per immediately above), ‘=’ has precedence over neither, but it does have precedence over ‘and’ thereby causing the subsequent version rewritten to use ‘and’ to then work as desired. You might want to read that back slowly!

      1. Whatever the point was, the demonstration of precedence through the use of brackets was wrong and will occasionally cause helpful people and pedants to search the comment thread to see whether the error has already been pointed out to the author. Guess what I just did?

      2. +1 to @crantok’s point, in the hope that OP will fix a glaring error at the very top of what is otherwise a good article. I too searched this thread, to see if anyone noticed that the claimed parsing/precedence is incorrect. It also confuses the issue a bit further down as one puzzles over the supposed “high precedence” of && in Ruby.

  12. 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.

      1. Actually it’s more an argument for language designers to be more careful when they copy features from other languages… The different precedence for AND and OR are virtually universal across nearly all languages. Even Perl, when the wordy operators were added, still took care to have different precedences.

        But I digress – I’m here because I was just bitten by another issue which hasn’t been mentioned. Which I’ll write in its own comment.

  13. Thanks for writing this up, Avdi. Even years later I find myself sending this post around to people as the de facto reference on “and/or” vs “&&/||”.

    Do you feel that the benefits of “and” and “or” as control flow operators are significant enough to merit using them, given how commonly confused they are with the binary operators? I’ve always felt a concern that someone will read them in code and, like me some years ago, mistake them for being synonyms and then use them incorrectly. As such I feel it’s safer to use && and || for control flow, adding parentheses where needed to alter their precedence.

    1. For better or for worse, Ruby is a very “big” language. I think if we are going to write all of our code with the newbie reader in mind (and that’s not an awful idea), we’d be better off using a smaller language like Python or a Lisp.

      That said, I think you have to be sensitive to context. In some projects the expectation may be that everyone knows their way around Ruby. In others, where teams are larger and/or there’s a lot of churn, it may be better to keep to a subset of the language.

  14. other strange thing with ‘and’ and && is return statement:
    [4] pry(main)> def foo
    [4] pry(main)* 1 and return
    [4] pry(main)* end
    => nil
    [5] pry(main)> def foo
    [5] pry(main)* 1 and return 1
    [5] pry(main)* end
    => nil
    [6] pry(main)> def foo
    [6] pry(main)* 1 && return
    [6] pry(main)* end
    => nil
    [7] pry(main)> def foo
    [7] pry(main)* 1 && return 1
    SyntaxError: unexpected tINTEGER, expecting kEND

  15. I’ve just been bitten by something like

    syntax error, unexpected kAND, expecting kTHEN or ‘:’ or ‘n’ or ‘;’ (SyntaxError)

      when params[:look] and params[:look] == "bootstrap"
                                                           ^
    

    where the ^ is pointing at the AND. I’m guessing now that the precedence is lower even that CASE, WHEN and friends, but I can’t find any mention in books so far. This has certainly surprised me. I’m going to do a few experiments later, and if this is true, I’ll add it to the list (of 3 items 😉 that I think are wrong with Ruby. I guess nothing is perfect; generally the syntax of Ruby is quite elegant and tidy. AND and OR strike me as a rushed afterthought.

  16. Can we just get one line, showing the order of precedence for all the relevant operators? So much easier than piecing together bits of rules in sentence form.

    A summary at the beginning and end.

    1. If you’re looking for that kind of reference info I suggest consulting the Ruby documentation. The point in this post is that if you need to know the precedence, you’re probably not using the operators to best effect.

  17. Thanks for this advice; it’s reassuring!

    I find ‘or’ useful in class initialize() constructors to raise exceptions if I’m not able to parse parameters and set mandatory instance variables:

    class A
    def initialize(x)
    @blah = $1 if x.match(/blah:([0-9]+)/) or raise “Missing mandatory blah”
    end
    end

    A.new(“test blah:123 test”)
    A.new(“test”) # => RuntimeError: Missing mandatory blah

    I haven’t found a cleaner way of doing this on one line and I have to ignore Rubocop’s advice to convert ‘or’ to ‘||’; the latter doesn’t even parse properly!

Leave a Reply to Matthew Willson Cancel reply

Your email address will not be published. Required fields are marked *