Do more in less time. Block distracting websites with Cold Turkey Pro (Windows, Mac) »

Create efficient C# if statements with logical short-circuit evaluation

For complex if statements, we often combine multiple true/false expressions. But we can usually structure those expressions so that C# does not need to evaluate all of them. Let’s see how that works and what its features are.

Process multiple C# true/false expressions efficiently

Complex if statements often have multiple Boolean expressions in their condition. The combination of all those true/false expressions has to be true before our program runs the if statement’s code. But that doesn’t mean all expressions have to be processed. Thanks to a C# feature we can ‘short-circuit’ the evaluation of a condition. That improves the performance of our code and can even save us from running into exceptions.

To understand that feature, let’s first look at two logical operators that combine true/false expressions (Sharp, 2013):

See combine if statement expressions with logical operators for more on these logical operators and how they work with C#’s if statements.

Besides combining expressions into a single true or false value, the && and || operators also perform something called short-circuit evaluation. With short-circuit evaluation, C# stops evaluating expressions when it can deduce the final outcome without them (Sharp, 2013; Stephens, 2014). In that case the logical test is “short circuited” (Stellman & Greene, 2010).

Say our program evaluates the A && B expression. When A is processed and turns up false, our program knows that A && B is false too. It knows this regardless of what value B has. And so there’s no need to check B because with A being false we already know the outcome of the expression.

A similar thing happens with the || logical operator. If our program comes across the A || B expression and A evaluates to true, then we also know the outcome of A || B: that expression got to be true as well.

Examples of C#’s short-circuit evaluation

To get a better idea of how short-circuit evaluation works, let’s look at two examples. As said above, && short circuits when its left expression is false (because the outcome will then always be false too).

Say we have a logical true/false expression like this:

(appDownloads > 100) && (appDownloads < 1000)

This piece of code checks if app downloads are between 100 (appDownloads > 100) and 1,000 (appDownloads < 1000). Before this true/false expression is true, the && operator requires that both logical comparisons are true.

Now say that the first test fails: appDownloads turns out to be 100 or less. That way appDownloads > 100 returns false. But this also means that the entire condition is false too. That happens because the logical AND operator (&&) needs both expressions to be true before their combination is true as well (Sharp, 2013).

And so when the first expression is already false, our program can infer that the && combination is false as well. That makes it short circuit and skip evaluating the second expression (appDownloads < 1000), simply because it already knows the outcome.

An example of the logical || operator is:

(appDownloads < 0) || (appDownloads > 1000000)

Here we check if the appDownloads variable has a valid value: it shouldn’t be negative, and when there are more than a million downloads in a day something is off too.

The logical || operator short circuits here as follows. Say that appDownloads is indeed less than 0. In that case the first expression returns true. Now || needs just one true expression to make the logical combination true as well. That means we already know the true/false outcome without even looking at the second expression. And so our program short circuits here and doesn’t even evaluate the appDownloads > 1000000 expression.

The short-circuit behaviour of the logical && and || operators has two benefits. It makes our true/false conditions more efficient since not every expression has to be computed. And with short circuiting we can even prevent exceptions. Let’s take a closer look at these two benefits.

Benefit 1: process C#’s if statements efficiently

The first benefit of short-circuit evaluation is greater speed. This happens because the second expression of the logical && or || operator doesn’t get evaluated when the Boolean outcome can already be inferred. For some code short-circuit evaluation doesn’t make any difference. But for time-consuming operations (like database actions or downloading data) the && and || operators make our code run quicker.

An example of where short-circuit evaluation gives a more efficient if statement is:

if (orderReceived && ConnectDatabase())
{
    // Update the database with the new order
}

Here we check two conditions before the indented code runs. Since we combine those with &&, both have to be true before the if statement’s condition is also true. The first expression is the orderReceived true/false variable, which signals that we need to update the database with new order information. The other expression is the ConnectDatabase() method, which returns true when the database connection is established.

The short-circuit logical && operator ensures that the second expression doesn’t get processed when the first one is already false. For the above if statement that means when there’s no new order, the relatively slow operation that connects to the external database doesn’t happen. And so the code only opens a database connection when we actually have something to update the database with. (And the if statement evaluates quicker when there’s no need to update the database.)

The && and || operators may have a side effect: when their evaluation short circuits, the second expression is skipped. That can have unintended consequences when we expect that second code part to run. To prevent those side effects, use the logical & and | operators instead (Stephens, 2014).

Short-circuit evaluation makes the logical && and || operators boost code performance by avoiding unnecessary work (Sharp, 2013; Stephens, 2014). We achieve that when we place simple expressions that can be evaluated quickly to the left of those logical operators. And place more complex expressions on the right. Then in many cases our program doesn’t need to evaluate the complex expression.

Benefit 2: prevent C# errors with short-circuit evaluation

Short-circuit evaluation not only makes if statements evaluate quicker. We can also prevent C# exceptions with it. Every so often we write code that can trigger an exception, like a potential division by zero. We usually deal with that by first verifying a value, and then perform the suspicious operation on it.

For that we can use two if statements: first check the value, then in a nested if statement perform the operation on it. Or we use short-circuit evaluation. With the logical && and || operators we can first make an if statement check a value and then act on that value. That validates the value before we use it, which prevents that value from triggering an exception (Liberty & MacDonald, 2009). After all, when the first expression is true (for ||) or false (for &&) then we know for sure that our program isn’t going to evaluate the second expression.

Let’s look at an example to make this more concrete. Say we want to calculate how many orders shipped on the same day. We could compute that like so:

if ((sameDayOrders / allOrders) > 0.80)
{
    Console.WriteLine("At least 80% of orders shipped out on the same day.");
}

In the condition of this if statement we divide the number of orders shipped on the same day (sameDayOrders) with the total amount of orders for this month (allOrders). Then we check if that fraction is greater than (>) 0.80.

But what if the total amount of orders is 0, like at the start of a new month? In that case this code triggers the DivideByZeroException error because we tried to divide by a variable with the value of 0 (allOrders).

Now we could make an if statement that checks allOrders followed by a nested if statement, like so:

if (allOrders > 0)
{
    if ((sameDayOrders / allOrders) > 0.80)
        Console.WriteLine("At least 80% of orders shipped out on the same day.");
}

This works fine, even though it gives some extra indentation and more lines of code. This can make our code less readable when we often need to check values before using them.

Luckily, we can also take advantage of the short-circuit behaviour of the logical AND operator (&&). For that we change the if statement to:

if (allOrders > 0 && (sameDayOrders / allOrders) > 0.80)
{
    Console.WriteLine("At least 80% of orders shipped out on the same day.");
}

This time we first evaluate whether the allOrders variable is greater than 0. With the logical AND operator (&&) we combine that with the expression that checks whether more than 80% of orders were fulfilled on the same day.

Because && performs short-circuit evaluation, when allOrders > 0 evaluates to false, our program doesn’t evaluate the second expression. Because that prevents the division by zero in the second expression, we don’t run into the C# exception anymore. In other words, this code still evaluates whether the percentage of orders shipped on the same day is greater than 80%. But now we first make sure we don’t divide by zero. And that prevents the arithmetic division by zero error.

Summary

Two logical operators that combine individual true/false values into a single true or false value are the logical AND (&&) and OR (||) operators. The logical AND operator (&&) returns true when the expression on its left and the one on its right are both true. When one or both are false, then this logical operator returns false too. The logical OR operator (||), on the other hand, returns true when its left expression, right expression, or both are true. Only when both the left and right values are false will || return false too.

Now a special feature of those logical && and || operators is that they can short-circuit logical expressions. When C# performs short-circuit evaluation, it skips evaluating an expression when it can already infer the final true or false outcome. That way our program doesn’t do unnecessary work.

Say the left value of the logical && operator is false. In that case we know that && returns false too. That’s because that logical operator returns true only when both values are true, and false when one or both values are false too. Whenever C# can infer the logical outcome based on &&’s left value, there’s no need to process the second expression. And so it short circuits.

A similar thing happens with the logical || operator. When the left value of this operator is true, || will return true too. We know that without even processing its right value. After all, || returns true when its left, right, or both the left and right values are true. And so C# can perform short-circuit evaluation when the first value of the || operator is true.

There are two main benefits to short-circuit evaluation. It makes our code more efficient because our program doesn’t need to evaluate extra expressions when it already knows the outcome. Another advantage is that short-circuit evaluation can help prevent errors. Since a logical comparison short circuits when the first expression is false (for &&) or true (for ||), the second expression doesn’t run. That way we can make sure the first expression checks the value that the second expression uses. And when it turns out the value is invalid, it won’t be used in the second expression thanks to short-circuit evaluation.

When our code should always evaluate both the left and right expressions, we use the equivalent & and | operators.

Learn more

  • Short-circuit evaluation increase code performance by not evaluating all expressions in a condition. Likewise, how we structure conditions in a cascaded if statement also affects performance. For that we save time-consuming conditions for later in the cascaded if statement, making it less likely the code needs to execute them.
  • Though short-circuit evaluation is a bit abstract, that’s nothing compared to how cryptic these two if/else statement alternatives look: the ternary operator and C#’s null-coalescing operator.

References

Liberty, J. & MacDonald, B. (2009). Learning C# 3.0: Master the Fundamentals of C# 3.0. Sebastopol, CA: O’Reilly Media.

Sharp, J. (2013). Microsoft Visual C# 2013 Step by Step. Microsoft Press.

Stellman, A. & Greene, J. (2010). Head First C#: A Brain-Friendly Guide (2nd edition). Sebastopol, CA: O’Reilly Media.

Stephens, R. (2014). C# 5.0 Programmer Reference. Indianapolis, IN: John Wiley & Sons.