Lably
Skip to content

Short-circuit evaluation

Programming language construct

  • 7 min read
  • 4 chapters

Related on Lably

Through Logical connective, Java (programming language) and Control flow

In programming languages with lazy evaluation (Lisp, Perl, Haskell), the usual Boolean operators short-circuit. In others (Ada, Java, Delphi), both short-circuit and standard Boolean operators are available. For some Boolean operations, like exclusive or (XOR), it is impossible to short-circuit, because both operands are needed to determine a result.

Short-circuit operators are, in effect, control structures rather than simple arithmetic operators, as they are not strict. In imperative language terms (notably C and C++), where side effects are important, short-circuit operators introduce a sequence point: they completely evaluate the first argument, including any side effects, before (optionally) processing the second argument. ALGOL 68 used proceduring to achieve user-defined short-circuit operators and procedures.

The use of short-circuit operators has been criticized as problematic:

The conditional connectives — "cand" and "cor" for short — are ... less innocent than they might seem at first sight. For instance, cor does not distribute over cand: compare

(A cand B) cor C with (A cor C) cand (B cor C);

in the case ¬A ∧ C , the second expression requires B to be defined, the first one does not. Because the conditional connectives thus complicate the formal reasoning about programs, they are better avoided.

— Edsger W. Dijkstra

Definition

In any programming language that implements short-circuit evaluation, the expression x and y is equivalent to the conditional expression if x then y else x, and the expression x or y is equivalent to if x then x else y. In either case, x is only evaluated once.

The generalized definition above accommodates loosely typed languages that have more than the two truth-values True and False, where short-circuit operators may return the last evaluated subexpression. This is called "last value" in the table below. For a strictly-typed language, the expression is simplified to if x then y else false and if x then true else y respectively for the Boolean case.

Precedence

Although AND takes precedence over OR in many languages, this is not a universal property of short-circuit evaluation. An example of the two operators taking the same precedence and being left-associative with each other is POSIX shell's command-list syntax.

The following simple left-to-right evaluator enforces a precedence of AND over OR by a continue:

<b id="mwYg">function</b> short-circuit-eval (<i id="mwYw">operators</i>, <i id="mwZA">values</i>) <b id="mwZQ">let</b> <i id="mwZg">result</i> := True <b id="mwZw">for each</b> (<i id="mwaA">op</i>, <i id="mwaQ">val</i>) in (<i id="mwag">operators</i>, <i id="mwaw">values</i>): <b id="mwbA">if</b> <i id="mwbQ">op</i> = "AND" && <i id="mwbg">result</i> = False <b id="mwbw">continue</b> <b id="mwcA">else if</b> <i id="mwcQ">op</i> = "OR" && <i id="mwcg">result</i> = True <b id="mwcw">return</b> <i id="mwdA">result</i> <b id="mwdQ">else</b> <i id="mwdg">result</i> := <i id="mwdw">val</i> <b id="mweA">return</b> <i id="mweQ">result</i>

Formalization

Short-circuit logic, with or without side-effects, have been formalized based on Hoare's conditional. A result is that non-short-circuiting operators can be defined out of short-circuit logic to have the same sequence of evaluation.

Comparison with bitwise operators

& and | are bitwise operators that occur in many programming languages. The major difference is that bitwise operations operate on the individual bits of a binary numeral, whereas conditional operators operate on logical operations. Additionally, expressions either side of a bitwise operator are always evaluated. In some languages, including Java and C#, they can be used on Boolean operands to force both sides to be evaluated.

<span id="mwig"></span><span class="k" id="mwiw">if</span><span class="w" id="mwjA"> </span><span class="p" id="mwjQ">(</span><span class="n" id="mwjg">expression1</span><span class="w" id="mwjw"> </span><span class="o" id="mwkA">||</span><span class="w" id="mwkQ"> </span><span class="n" id="mwkg">expression2</span><span class="w" id="mwkw"> </span><span class="o" id="mwlA">||</span><span class="w" id="mwlQ"> </span><span class="n" id="mwlg">expression3</span><span class="p" id="mwlw">)</span>

If expression 1 is true, expressions 2 and 3 are not checked.

<span id="mwmw"></span><span class="k" id="mwnA">if</span><span class="w" id="mwnQ"> </span><span class="p" id="mwng">(</span><span class="n" id="mwnw">expression1</span><span class="w" id="mwoA"> </span><span class="o" id="mwoQ">|</span><span class="w" id="mwog"> </span><span class="n" id="mwow">expression2</span><span class="w" id="mwpA"> </span><span class="o" id="mwpQ">|</span><span class="w" id="mwpg"> </span><span class="n" id="mwpw">expression3</span><span class="p" id="mwqA">)</span>

This checks expressions 2 and 3, even if expression 1 is true.

Short-circuit operators can thus reduce run times by avoiding unnecessary calculations. They can also avoid null exceptions when expression 1 checks whether an object is valid.

Sign in to keep reading

3 more chapters are free with a Lably account.

More in Computing and communication