(This question is, of course, another thrilling installment of “The history of expression evaluation”; see the previous episodes here and here.)
In many programming languages, the Boolean operators ∧ and ∨, however they are spelled (and
, &&
, or
, ||
), evaluate their operands only as necessary. For example, if the first operand of ∧ is false, then no value of the second operand can make the result of the expression true. And if the first operand of ∨ is true, then the second operand need not be inspected at all, since the result is guaranteed to be true. This property is often referred to as “short-circuiting”.
It comes in handy in code like
if (x > 0) ∧ (a/x < 12) then …
because the expression a/x is undefined if x = 0. It can also improve efficiency, if evaluating some of the operands would be computationally expensive.
The first language to support short-circuiting was the first language to have any notion of “Boolean expressions” at all: Lisp. (See page 22 of the LISP 1.5 Programmer's Manual.) What was the second language, not counting some dialect of Lisp?
Here are some notes on the subject. I'm putting them here in case they might be of use to anyone else interested in this sort of thing.
In Algol 60, Boolean operators were not short-circuiting, because…actually I don't know why. McCarthy was one of the language's designers, after all. I suppose you can get the same effect with something like
if if (x > 0) then (a/x < 12) else false then …,
but this is a little less elegant.
In Algol 68, Boolean operators are also not short-circuiting. One way to look at it is to consider that operators are not really different from procedures in Algol 68, and all arguments actual-parameters in procedure calls are always evaluated elaborated. Furthermore, if an exception were made for Boolean operations, then ∧ and ∨ could not be defined within the language using an operation-declaration.
There's a bit more to the story, however. When McCarthy was still a part of the committee designing the language, he wanted short-circuiting, even though it was at odds with the strict rules of evaluation elaboration that had been agreed upon. Instead of changing the fundamentals of the language, a new type of coercion, called “proceduring”, was introduced, which would essentially “thunkify” operands, allowing their evaluation elaboration to be delayed. An example from an early report was
op cand = (bool john, proc bool mccarthy) bool: if john then mccarthy else false fi;
Thus a bool as the second operand of cand would be “procedured” into a proc bool, which would be called only if the first operand is true. Eventually proceduring was dropped from the language, because “it complicated the syntax considerably (it is necessary to avoid cycles of proceduring and deproceduring) and it was a pain to implement”. (Source: section 2.3.3.6 in C. H. Lindsey, “A history of ALGOL 68”, History of programming languages—II.)
As in Algol 60, you can use a conditional expression conditional-clause; the if if example is also valid in Algol 68 (if you add a terminating fi). A convenient shorthand notation was introduced, so that
if (x > 0 | a/x < 12 | false) then … fi
is equivalent to the previous form.