Saturday 22 November 2014

Short-circuit Boolean Evaluation

A useful but often not thought about feature is that many programming languages, including C#, support short-circuit evaluation of Boolean expressions. For example, in the following logical AND condition:

if (OperandOne && OperandTwo) 
{    
}

OperandTwo is only evaluated if OperandOne equals the Boolean value of true. If OperandOne's value is false, then the entire condition evaluates to false regardless of the value of any other operand in the condition (basic boolean algebra). Hence, there is no reason to continue evaluating the subsequent operands. This functionality is known as short-circuiting. You can confirm this language feature in C# with some basic code:

void Main()
{
    if (MethodOne() && MethodTwo())
    {
    }
}

bool MethodOne()
{
    Console.WriteLine("MethodOne: I got evaluated!");
    return false;
}

bool MethodTwo()
{
    Console.WriteLine("MethodTwo: I got evaluated!");
    return true;
}

After executing the code above, you'll see that the Console.WriteLine call in MethodOne only gets called. Short-circuit evaluation also works for the logical OR operator. Let's change the condition in the above code snippet to look like:

if (MethodOne() || MethodTwo())
{
}

If you now execute the code, you'll see that both of the Console.WriteLine calls in MethodOne and MethodTwo get called. However, if you now change MethodOne to return true and re-execute, you'll see that C#'s short-circuit evaluation kicks-in and only the Console.WriteLine in MethodOne gets executed.

Short-circuit evaluation gives you, as the programmer, a neater way to express your code. For example, without short-circuit evaluation, you wouldn't be able to construct conditions such as:

if (person != null && person.Age > minimumAge)
{
}

In this condition, a check is first made to ensure the person object isn't null before we go ahead and try to access the Age property on the object. If the person object is null, then the short-circuiting kicks-in and prevents the incorrect access of the Age property (which would result in a NullReferenceException to be thrown).

A lesser known nuance of C# is that short-circuit evaluation can be bypassed as a side effect of using the bitwise operators & and | without losing the semantics of the logical operation. For example, if we reuse our code snippet from earlier and make a minor adjustment to the condition to use the bitwise AND operator, we'll have:

void Main()
{
    if (MethodOne() & MethodTwo())
    {
    }
}

bool MethodOne()
{
    Console.WriteLine("MethodOne: I got evaluated!");
    return false;
}

bool MethodTwo()
{
    Console.WriteLine("MethodTwo: I got evaluated!");
    return true;
}

After executing the snippet above, you'll now see that both the Console.WriteLine in each of MethodOne and MethodTwo get called despite MethodOne (the first operand) returning false. Using a single & over && does not affect the semantics of the logical AND operator - so the code within the braces of the if-condition would still not get executed in this case (as the entire expression still evaluates to false). However, the key thing to note is that all operands are evaluated when bypassing short-circuit evaluation. Similar to the single & operator, short-circuit evaluation is also bypassed when using a single | (bitwise OR) without losing the semantics of OR.

It is generally advised not to bypass short-circuit evaluation but I find that it is important to be aware of it to catch bugs. In the past, I have noticed on several occasions that subtle bugs were introduced where a developer has used a single & and one of the operands in the expression had a side effect (e.g. a method that performs an action). Perhaps they came from a non-short-circuit-featured language where the single character versions of && and || are used to express logical AND and OR?. Take the following code snippet as an example:

if (person.HasChanges & _repository.UpdatePerson(person))
{
    ...
}

In this case, the UpdatePerson method will always be called, even when the person object states that it has no changes. This is a subtle bug which can easily be missed. Nevertheless, it is fixed by using the && operator to make use of short-circuit evaluation!