Back to Basics: Boolean Expressions

If your only tool is a hammer, then every problem looks like a nail

Folk saying

if / else expressions are a powerful tool that allow us to express conditional logic. However, when it comes to returning Booleans they are generally the wrong tool for the job. They can be redundant or, worse, obscure the meaning of what is being done.

Identity

This is a mistake I often see brand new programmers fall into. If you’re looking to write an if/else, it’s natural to express “admins can edit and others cannot” as the following conditional:

def can_edit?
  if admin?
    true
  else
    false
  end
end

On closer inspection though, we can see that the conditional code is redundant. It just returns the value that the Boolean already holds. Instead, we can return the Boolean directly without doing any logic.

def can_edit?
  admin?
end

Negation

This one is very similar to the “identity” conditional shown above but the branches are flipped. When admin? is true we return false and when it is false we return true.

def reader?
  if admin?
    false
  else
    true
  end
end

We have an operator the does the same thing: ! (NOT). Much shorter and easier to read now!

def reader?
  !admin?
end

Early returns

Ruby syntax allows for combining early returns with a postfix conditional to create really terse conditional logic. If you’re using this approach to return different Booleans, you’re probably better off using the Boolean operations instead. Consider the following:

def reader?
  return false if admin?
  true
end

This is the same negation conditional we saw above. It’s much terser but also really hard to read. As before, this is re-implementing the ! (NOT) operator.

def reader?
  !admin?
end

Multiple variables

Boolean methods expressed as a series of early returns can be very difficult to read, especially once you have a few different variables. Often, they may hide some very basic Boolean operations. Consider the following:

def can_edit_admin_post?
  return owner? unless admin?
  true
end

It’s really tricky to follow the interplay between the two conditions. Who is able to edit admin posts and under what conditions? Even with only two variables I struggle to answer that question.

It turns out that this conditional code was re-implementing the Boolean || (OR) operator. Now try and explain who can edit. Much easier!

def can_edit_admin_post?
  owner? || admin?
end

Let’s scale it up to 3 variables. Here’s an example inspired by some code on a recent project that really confused me 😱🙀😱

def can_edit?(article)
  return false unless article.status == "published"
  return true if admin?
  return false unless article.authored_by?(self)
  true
end

Truth tables

So you’ve encountered a confusing Boolean conditional method (maybe you’ve written it yourself!). How can you get a grasp of what is happening? One tool I like is the truth table. Create columns for all the inputs covering all the combination of true/false values. Then calculate the outcome for each row and add it in the final column. The result will look as follows:

owner? admin? can_edit_admin_post?
false false false
false true false
true false false
true true true

I find this very useful to get a better overview of how a method behaves. Sometimes patterns for common operations stand out. In the example above, the output column is always false except for the row that is all true values. That’s the same pattern as for && as can be seen in the truth table below.

a b a && b
false false false
false true false
true false false
true true true

Write Boolean expressions

The operators !, ||, and && give us powerful tools for working with Boolean expressions. Add them to your toolbelt! The next time you are writing a method that returns Booleans you’ll have something other than if/else to reach for.