C# Boolean Expressions With and Without Short-Circuiting

For years I’ve used the && and || operators in C# Boolean expressions (e.g. if (age > 60 && gender == male) { /* do something */ }). Today, I was surprised to learn that & and | can also be used to compare bool values (this is in addition to their traditional use as bitwise AND and OR operators).

What’s the difference between the two pairs of operators? && and || use short-circuit evaluation while & and | do not.

Under short-circuit evaluation (&& and || operators), expression evaluation stops as soon as a conclusive result is determined. The entire condition statement may not be executed. In the case of if (alwaysReturnsFalse() && somethingElse()) { /* … */ }, method somethingElse() will never be called. Why? The fact that the left operand (the call to alwaysReturnsFalse()) evaluates to false is sufficient information to conclude that the entire expression evaluates to false. The call to somethingElse() is unnecessary and so is skipped over (or short-circuited).

With non-short-circuit comparison (& and | operators), the entire expression is always evaluated. When if (alwaysReturnsFalse() & somethingElse()) { /* … */ } is executed, somethingElse() will always be called because short-circuiting will not occur.

Which to use?

For performance reasons, using && and || is preferable because unnecessary evaluations are skipped (i.e. unnecessary work is avoided).

Short-circuiting can also be used to concisely code statements where one condition must only (or must never) be evaluated if the proceeding condition is true. Suppose we want to check if a variable of type IList is either null or references an empty list. Short-circuiting allows us safely to write if (list == null || list.Count == 0). If list is null, the call to list.Count is short-circuited—important because calling Count on a null list will result in a NullReferenceException. Without short-circuit evaluation, we’d need to write something along the lines of if (list == null) { /* … */ } else if (list.Count == 0) { /* .. */ } to achieve the same effect.

Leave a Reply

Your email address will not be published. Required fields are marked *