Boolean Operators

Simple boolean expressions will only get you so far. What if you want to take a certain action if someone is older than eighteen, but younger than sixty-five? You might be able to do something with a range (like (18..16).include?(person.age)), but not all of these situations are quite so simple. As with most programming languages, you'll need to use boolean operators.

Boolean operators are quite simple.

The and operator takes two operands and evaluates to true if both of its operands are true. Similarly, the or operator takes two arguments and evaluates to true if either of the operands are true. More commonly, you'll see these operators in their symbolic form: && (two ampersands) for the and operator and || (two pipe characters) for the or operator. Though they appear to be the same at first, don't use them interchangeably (see below).

In addition to && and ||, there's also a ! or not operator. It's a unary operator (like the negative operator, it precedes its operand) and reverses the truthiness of its operand. Pass it something true and it will evaluate to false. Pass it something false and it will evaluate to true. This operator is not used all that often though, as the == has a != counterpart, >= has , etc. Even the conditionals have counterparts that have reverse meaning, like if and unless. Using these operators and alternative conditionals is often more clean than using the not operator. Though you will see it in Ruby code, especially when testing if a single boolean value is true or false.

To begin playing with the && and || operators, you can start feeding it true and false in irb. Also note that you can build more and more complex statements using parentheses. However, don't get carried away, and this quickly becomes unreadable.

irb(main):001:0> true && true
=> true
irb(main):002:0> true && false
=> false
irb(main):003:0> true && !false
=> true
irb(main):004:0> true || true
=> true
irb(main):005:0> true || false
=> true
irb(main):006:0> false || true
=> true
irb(main):007:0> false || false
=> false
irb(main):008:0> !false || false
=> true

You'll typically use these types of boolean expressions with boolean operators in conditional statements. Where a new programmer might try to "nest" conditional statements, you can use these conditional operators to do the same thing more compactly and more expressively. However, the warning above still holds: if you're using a lot of boolean operators in the same expression, it gets unreadable very quickly. The trick there is to use Ruby's freeform nature to insert whitespace and indentation to make it readable. Another option is to pre-calculate portions of the boolean statement and store the results in variables so the boolean expression itself is more readable. And, finally, the last option is to refactor. Do you really need to be doing such a large boolean expression? There are sometimes better ways to do things.

#!/usr/bin/env ruby

alice = {
  :name => 'Alice',
  :age => 27,
  :occupation => 'Rubyist',
  :hobby => 'Yak Shaving'

bob = {
  :name => 'Bob',
  :age => 51,
  :occupation => 'Sysadmin and Rubyist',
  :hobby => 'Promoting OS/2'

# Admit someone to the secret society?
def admit(person)
  if (
    (person[:age] > 18 && person[:age] 

Operator Precedence and Shortcut Behavior

It was mentioned above that the operators have two forms: symbolic (&& and ||) and keyword (and and or) and that they were different somehow.

They differ only in operator precedence. The symbolic versions have a higher operator precedence, they "bind more tightly." They're used for often for this reason, as lower precedence operators are more likely to bind in an unexpected manner.

Whatever you do, don't mix the two and expect things to work as intended. Since the symbolic versions have higher precedence, how the operators bind and in what order they're evaluated can be difficult to tell at a glance. Also, and and && operators have slightly higher precedence than or and || respectively. When in doubt, simplify your boolean expressions or add more parentheses. When a boolean expression with boolean operators binds incorrectly, it's not an error as far as Ruby is concerned. It will gladly evaluate it wrong (or at least not in the way you intended) and it will be a difficult bug to track down.

It might even work correctly most of the time and even survive all of your tests.

Though they're not often used in boolean expressions, they're sometimes used as conditional operators themselves. This leverages Ruby's boolean operator shortcut behavior. When evaluating whether an or operator is true or false, it evaluates the left-hand side first. If it's true, it doesn't matter what the right hand side is so it isn't evaluated. You can use this to your advantage by saying things like widget.perform() or puts("Widget failed to perform"). This is something borrowed from Perl, where this is common practice. It's not very common in Ruby as Ruby also has reverse conditional expressions. The above example can be written as puts("Widget failed to perform") unless widget.perform(), however it doesn't read quite as well.