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.