Understanding Short-Circuit Evaluation in Software Design

Understanding Short-Circuit Evaluation in Software Design Featured Image

When it comes to organizing your logic in a program, one tool that can do a lot of heavy lifting for you is short-circuit evaluation. In this article, I’ll give a little bit of background around short-circuit evaluation, describe what short-circuit evaluation is, and why I think you should use it. Let’s get into it!

Table of Contents

Background

In most programming languages, we have constructs that enable us to compute boolean expressions. A boolean expression is any expression which evaluates to true or false—even if the subexpressions contain values that aren’t booleans (i.e., numbers, strings, functions, etc.). Here are a few examples from my favorite programming language, Python:

5 < 6  # Evaluates to True
True and False  # Evaluates to False
not True or 17 > 4  # Evaluates to True
bool([])  # Evaluates to False
5 > 6 > 7  # Evaluates to False

As you can see, boolean expressions can come in many forms from arithmetic comparisons to function calls. Naturally, it’s probably no surprise that boolean expressions are extremely useful. In fact, we often use them when we wish to branch in our code (e.g., loops, if statements, etc.). As a result, programming languages often have a lot of tricks to make these expressions as powerful and expressive as possible. One of those tricks is the topic of today’s article: short-circuit evaluation.

What Is Short-Circuit Evaluation?

In a previous article, I had written about flags and why I recommend folks to avoid them. Interestingly, one of the best arguments against flags is missing out on the beauty of short-circuit evaluation. Let’s look at an example:

positive_number = -1
flag = true
while flag:
  user_input = input("Give me a positive number: ")
  if user_input.lstrip("-+").isdigit():
    positive_number = int(user_input)
    if positive_number > 0:
      flag = true

In this example, we’re trying to get the user to provide us with a positive number. If we get anything other than a positive number, we prompt the user again. To make sure we have a positive number, we first have to make sure we have a number. Only then can we convert the string to an integer to check if it’s positive.

As an educator, I see this type of code a lot with beginners. It seems they understand branching with if statements really well, but they have trouble transitioning that same idea to loops. Funnily enough, there’s a really clean solution that involves shifting these two conditions to the loop condition:

user_input = input("Give me a positive number: ")
positive_number = -1
while not user_input.lstrip("-+").isdigit() and int(user_input) <= 0:
  user_input = input("Try again: ")
positive_number = int(user_input)

And of course, there are a dozen of other ways to accomplish the solution. That said, I chose this one to demonstrate the concept for the day: short-circuit evaluation.

Previously, we had a series of nested if statements. The idea behind these if statements is that we care a lot about the order of their execution. If the first one fails, we don’t want to even attempt the second one. Otherwise, our program would crash:

>>> int("dfas")
Traceback (most recent call last):
  File "<pyshell#10>", line 1, in <module>
    int("dfas")
ValueError: invalid literal for int() with base 10: 'dfas'

Of course, nesting if statements is a pain, and every time we add a level of indentation we introduce complexity. As a result, I prefer to lean on short-circuit evaluation. The idea is that we can accomplish the same exact thing as nesting through careful ordering of our boolean expressions. For example, we could combine our previous if statements as follows:

positive_number = -1
flag = true
while flag:
  user_input = input("Give me a positive number: ")
  if user_input.lstrip("-+").isdigit() and int(user_input) > 0:
    positive_number = int(user_input)
    flag = true

Now, instead of nested if statements, we have one if statement where the two conditions we care about are bound by a single boolean operator (and). With AND specifically, if we know the first value evaluates to false, we can stop evaluating; the entire expression is false. Here’s the truth table if you don’t believe me:

XYOutput
truetruetrue
truefalsefalse
falsetruefalse
falsefalsefalse
AND Truth Table

As you can see, any time the first value is false, we can assume the output will be false. We know this because AND will only return true when both values are true. Knowing this fact, we can cheat a bit when we evaluate expressions. As soon as the first value comes out false, we stop evaluating. That’s short-circuit evaluation.

As you can probably imagine, a similar argument can be made for the OR operator. In that case, if the first value comes out as true, the whole expression is true. No need to worry about checking if the second expression is also true.

Why Take Advantage of Short-Circuit Evaluation?

Hopefully, through the example above, you know of at least one use for short-circuit evaluation. To be more explicit, we use the trick to avoid crashing our program if some condition ends up false. Another common place this happens is with null checks. If you want to run a method on an object but not sure if it’s null, use short-circuit evaluation:

if car is not None and car.is_totaled():
  print("At least I can scrap it for parts!")

Sometimes, you’re less concerned about crashes and more concerned about time consuming operations:

if not is_even(num) and not is_prime(num):
  print("We have a composite number!") 

In this example, we check if a number is not even and not prime, but we’re strategic with which one we check first. Checking if a number is even is usually an inexpensive task. On the other hand, checking if a number is prime is a bit more time consuming. To save time, we avoid checking if the even numbers are prime.

Surely, there are other use cases, but my general approach to short-circuit evaluation is to protect myself from errors and speed up my programs. As an added bonus, the trick tends to clean up code a bit. No more pesky nesting: only boolean expressions.

At any rate, hopefully this helped you make sense of the concept of short-circuit evaluation. It’s a handy trick that I recommend using to simplify your code when possible. If you liked this trick and want to learn more coding tricks, check out some of these related posts:

While you’re hear, I’d appreciate it if you took some time to support the site. If not, no worries! I’ll see you next time.

Coding Tangents (43 Articles)—Series Navigation

As a lifelong learner and aspiring teacher, I find that not all subjects carry the same weight. As a result, some topics can fall through the cracks due to time constraints or other commitments. Personally, I find these lost artifacts to be quite fun to discuss. That’s why I’ve decided to launch a whole series to do just that. Welcome to Coding Tangents, a collection of articles that tackle the edge case topics of software development.

In this series, I’ll be tackling topics that I feel many of my own students have been curious about but never really got the chance to explore. In many cases, these are subjects that I think deserve more exposure in the classroom. For instance, did you ever receive a formal explanation of access modifiers? How about package management? Version control?

In some cases, students are forced to learn these subjects on their own. Naturally, this forms a breeding ground for misconceptions which are made popular in online forums like Stack Overflow and Reddit. With this series, I’m hoping to get back to the basics where these subjects can be tackled in their entirety.

Jeremy Grifski

Jeremy grew up in a small town where he enjoyed playing soccer and video games, practicing taekwondo, and trading Pokémon cards. Once out of the nest, he pursued a Bachelors in Computer Engineering with a minor in Game Design. After college, he spent about two years writing software for a major engineering company. Then, he earned a master's in Computer Science and Engineering. Today, he pursues a PhD in Engineering Education in order to ultimately land a teaching gig. In his spare time, Jeremy enjoys spending time with his wife, playing Overwatch and Phantasy Star Online 2, practicing trombone, watching Penguins hockey, and traveling the world.

Recent Posts