Open davedelong opened 2 years ago
It does short-circuit, but as you say, "a typical optimization of || and && statements is to not execute the right-hand-side of the operator if the final value can be deduced from the left-hand-side." Since you call potentiallyExpensiveLookup(...)
first, it will be evaluated before checking maybe == true
. What I think you are looking for is for the compiler to re-order those comparisons in a way which removes the lookup call.
Re-ordering code in order to entirely remove function calls is quite tricky IIUC, because potentiallyExpensiveLookup
might have side-effects.
However, the optimizer should be able to see that:
if let value = potentiallyExpensiveLookup(...), maybe == true { // true branch } else { // false branch }
is logically equivalent to:
if maybe == true { if let value = potentiallyExpensiveLookup(...) { // true branch } else { // false branch } } else { // false branch }
Because of side-effects that @karwa mentioned, is very hard to make that "logically equivalent" assumption.
Also, IIRC correctly ordering if let
clauses and boolean check in if statements is already a syntax supported so it is possible to right code like
func potentiallyExpensiveLookup(_ key: String) -> Int? {
print("Performing expensive lookup")
return key == "42" ? 42 : nil
}
func doTheThing(_ maybe: Bool) {
if maybe == true, let value = potentiallyExpensiveLookup("0") {
print("Matched: \(value)")
} else {
print("Did not match")
}
}
Which this equivalence assumption can be correct and the ordering is up to the user in the same way normal all boolean &&
works.
Comma-separated statements in an if-let statement are logically AND'ed together. A typical optimization of
||
and&&
statements is to not execute the right-hand-side of the operator if the final value can be deduced from the left-hand-side. For example in C, this is a common pattern to avoid dereferencingNULL
:However, no optimization happens with if-let statements. Consider the following code:
If this example is run with
doTheThing(false)
, we can look at the code and see the the value retrieved frompotentially ExpensiveLookup()
will never be used, because themaybe == true
condition will always evaluate to false.In every optimization mode (
-O0
,-O1
,-O2
,-O3
,-Os
,-Ofast
,-Oz
), runningdoTheThing(false)
results in this output:However, the optimizer should be able to see that:
is logically equivalent to:
The optimizer should be able to recognize explicit boolean comparisons in if-left statements that do not rely on previously-bound values, and rewrite the expression to evaluate those first. This would allow programs to avoid executing potentially expensive lookups that are unnecessary.