Discussion:
Shortcut Booleans
Add Reply
Lawrence D'Oliveiro
2024-06-07 10:52:51 UTC
Reply
Permalink
I wonder why, traditionally, shortcut evaluation of boolean subexpressions
has been applied to “and” and “or” connectives, but not any others.

For example, what about “implies”?

a implies b

Truth table:

a b result
------------
0 0 1
0 1 1
1 0 0
1 1 1

But C does not have an “implies” operator, I hear you say? Of course this
can be written

not a or b

and shortcut evaluation would apply. But it can also be written

a <= b

and shortcut evaluation would *not* apply. Why not, if a and b are
boolean-valued subexpressions?
bart
2024-06-07 12:41:06 UTC
Reply
Permalink
Post by Lawrence D'Oliveiro
I wonder why, traditionally, shortcut evaluation of boolean subexpressions
has been applied to “and” and “or” connectives, but not any others.
Common sense applies, otherwise you could shortcut these operations:

a * b // when a is zero, the result is zero
a & b // when a is zero

Here you would probably spend more time checking the value of 'a' then
branching, than just doing the operation.

The language chooses to specify that both operands are always evaluated.
That is the most useful behaviour.

Short-circuiting logical ops are mainly associated with conditional
expressions used for branching, such as in 'if', 'while', 'for' statements.

If both operands always had to be evaluated, then code would be
inefficient as it would need to create an actual result:

if (f() && g())

Not only would both functions be called, but you'd need to combine the
results which means remembering the value of f().


(I have played with a logical and/or operators that didn't have
short-circuit semantics; they worked like this:

if f() andb g()

('andb' means 'and-both'.) But I already had too many such features and
eventually it was dropped.

My 'andb' example be trivially expressed in other ways, such as in this C:

if (!!f() & !!g())

)
Post by Lawrence D'Oliveiro
For example, what about “implies”?
a implies b
What about it? I've never used that, ever. I doubt many have.

If it can be rewritten 'not a or b' then just use that.
Lawrence D'Oliveiro
2024-06-08 02:42:15 UTC
Reply
Permalink
Post by bart
a * b // when a is zero, the result is zero
a & b // when a is zero
And why not? It would depend on the complexity of the “a” and “b”
subexpressions, of course.
David Brown
2024-06-09 11:35:12 UTC
Reply
Permalink
Post by Lawrence D'Oliveiro
Post by bart
a * b // when a is zero, the result is zero
a & b // when a is zero
And why not? It would depend on the complexity of the “a” and “b”
subexpressions, of course.
The language defines "shortcutting" for operators so that you know
whether "a" and "b" will both be evaluated, or just one of them.
Understanding these is vital to making your code correct.

Whether the implementation /actually/ evaluates "a" and "b", and in what
order, is a matter of implementation efficiency - as long as it
generates results that have the correct observable behaviour.

In general, it would be inconvenient if you did not know whether "a @ b"
was going to evaluate "b", including all function calls and side-effects.
Lawrence D'Oliveiro
2024-06-10 01:51:30 UTC
Reply
Permalink
Post by David Brown
was going to evaluate "b", including all function calls and
side-effects.
Ada has “and then” and “or else”, so that you can specifically request
shortcut evaluation when program correctness depends on it, and leave it
up to the implementation otherwise.

This principle could be extended to other situations ...
Keith Thompson
2024-06-10 02:24:22 UTC
Reply
Permalink
Post by Lawrence D'Oliveiro
Post by David Brown
was going to evaluate "b", including all function calls and
side-effects.
Ada has “and then” and “or else”, so that you can specifically request
shortcut evaluation when program correctness depends on it, and leave it
up to the implementation otherwise.
Note that Ada's "and" and "or" operations are required to evaluate both
operands; it isn't up to the implementation to decide to short-circuit
them (except when it doesn't change the program's behavior, like any
other optimization).
Post by Lawrence D'Oliveiro
This principle could be extended to other situations ...
Yes, it could, but I don't think it would be worthwhile for operations
other than "and" and "or".

Do you have examples that are compelling enough to justify a new
language feature, especially given that you can already write
(x == 0 ? 0 : x * y)?
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+***@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
Loading...