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]

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.

    • http://wideteams.com Avdi Grimm

      Indeed :-) Thanks for the comment.

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

    • http://wideteams.com Avdi Grimm

      Good luck!

  • Chrisr

    Thanks, I always wondered the difference

    • http://wideteams.com Avdi Grimm

      You're welcome!

  • seydar

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

    • http://wideteams.com Avdi Grimm

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

  • Jason the Saj

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

    LOL

    • http://wideteams.com Avdi Grimm

      :-P

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

    • http://wideteams.com Avdi Grimm

      Yeah, the first example usually reads better as:

      do_something if/unless condition?

      Glad you liked it!

  • Jon Atack

    Thanks, Avdi, that was a good reminder.

    • http://wideteams.com Avdi Grimm

      :-)

  • 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”

      • 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://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://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://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.

        • 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://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.

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

    • 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://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

        • 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

          • Mindtonic

            ^ Nice example of another use of 'and'

          • 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://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://www.kuhnsfam.com metavida

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

  • 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

    • http://wideteams.com Avdi Grimm

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

      • 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

  • Nothing

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

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

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

    • 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://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://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.

      • Dave Kroondyk

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

        • http://avdi.org Avdi Grimm

          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.

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

    • http://wideteams.com Avdi Grimm

      Glad I could help!

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

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

    • http://wideteams.com Avdi Grimm

      You're welcome!

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

    • http://wideteams.com Avdi Grimm

      No problem ;-)

  • 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

    • Exolon

      I think you got them the wrong way around.

  • 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://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.

    • 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)

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

  • 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

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

    • http://avdi.org Avdi Grimm

      This is a good justification for never, ever using both ‘and’ and ‘or’ in the same line.

      • Andrew Clarke

        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.

  • http://rob.by/ Robby Grossman

    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.

    • http://avdi.org Avdi Grimm

      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.

  • http://perryhuang.com/ Perry Huang

    Thanks. This was the #3 search result on Google for “ruby and operator”. :)

  • Andrey

    Great post. Thank you!

  • michal

    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

  • Andrew Clarke

    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.

  • gwhosubex

    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.

    • http://avdi.org Avdi Grimm

      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.