The Tip of the Ruby #1

Posted by Curtis Miller Curtis Miller

I was recently asked about the difference between using or versus || in Ruby and thought it might make a good tip. They essentially do the same thing, but with one difference: operator precedence. You see || is evaluated before an assignment whereas or is evaluated after an assignment. This is why you can create conditional assignments like so:

user = User.find_by_id(1) || User.new

In the above code, if a user is found, then the variable is assigned that user. If a user is not found, then find_by_id returns nil (evaluates to false) and a new User is instantiated and assigned to the variable. If you were to use or in the code above, then when find_by_id returned nil the variable would be assigned nil as the assignment operator takes precedence over the or operator.

Example

Here's a contrived example to show the difference between the two. Given the following class:

class Tester
  def self.a
    p "In Tester.a"
    return true
  end

  def self.b
    p "In Tester.b"
    return false
  end
end

Here are some expressions and their results:

>> x = Tester.a || Tester.b
"In Tester.a"
=> true
>> x
true
x = Tester.a or Tester.b
"In Tester.a"
=> true
>> x
=> true

So far they look identical… But, let's change the order things are invoked.

>> x = Tester.b || Tester.a
"In Tester.b"
"In Tester.a"
=> true
>> x
=> true
>> x = Tester.b or Tester.a
"In Tester.b"
"In Tester.a"
=> true
>> x
=> false

Now we see the difference! When the invocation of Tester.b finishes, then the assignment operator is invoked, thus assigning false to the variable. Notice that Tester.a is still invoked, but it is ORed with the result of the assignment.

Lazy (Shortcircuit) Evaluation

I was also asked if the conversational operators are always evaluated. The answer is: No. The are evaluated just as the non-conversational operators. From Programming Ruby, 2nd Edition:

Both and and && evaluate to true only if both operands are true. They evaluate the second operand only if the first is true (this is sometimes known as shortcircuit evaluation). The only difference in the two forms is precedence (and binds lower than &&).

Similarly, both or and || evaluate to true if either operand is true. They evaluate their second operand only if the first is false. As with and, the only difference between or and || is their precedence.

Precedence of and and or

There is one other minor difference. The && operator takes precedence over the || operator so if you had an expression containing both, the && should evaluate first. With and and or they should be evaluated at an equal precedence, probably in the order they're encountered.

Conclusion

I use the conversational not/and/or because I feel they make the code easier to read and force you to be explicit to account for the low operator precedence. I tend to use !/&&/|| sparingly (like using || for conditional assignment). Also, with compound expressions, I like to use parenthesis for clarity. Am I missing something? Do you know of a reason to prefer one or the other?

Update: Jay Fields has a post about this same topic. Marcel Molina, Jr. said in the comments that he prefers not to use either form as it is easy to introduce subtle errors.



Velocity Labs

Need web application development, maintenance for your existing app, or a third party code review?

Velocity Labs can help.

Hire us!