Here's a real world use case (that could end up in the Standard Library).
It overrides the default O(n) implementation of distance(from:to:)
with an O(1) implementation for a zip
that takes default values:
func distance (from start: Index, to end: Index) -> Int {
if start == end {
return 0
}
let distance1 = collection1.distance(from: start.index1, to: end.index1)
let distance2 = collection2.distance(from: start.index2, to: end.index2)
if start < end {
return Swift.min(
defaultElement1 == nil ? distance1 : Swift.max(distance1, distance2),
defaultElement2 == nil ? distance2 : Swift.max(distance1, distance2)
)
} else {
return Swift.max(
defaultElement1 == nil ? distance1 : Swift.min(distance1, distance2),
defaultElement2 == nil ? distance2 : Swift.min(distance1, distance2)
)
}
}
The ternary operator already helps us out here; if no defaultElement
s exist, the calls to Swift.max(_:_:)
and Swift.min(_:_:)
will not be made. However, if both Collection
s have defaultElement
s, then either will be computed twice.
With lazy var
s this could be rewritten as:
func distance (from start: Index, to end: Index) -> Int {
if start == end {
return 0
}
let distance1 = collection1.distance(from: start.index1, to: end.index1)
let distance2 = collection2.distance(from: start.index2, to: end.index2)
if start < end {
lazy var max = Swift.max(distance1, distance2)
return Swift.min(
defaultElement1 == nil ? distance1 : max,
defaultElement2 == nil ? distance2 : max
)
} else {
lazy var min = Swift.min(distance1, distance2)
return Swift.max(
defaultElement1 == nil ? distance1 : min,
defaultElement2 == nil ? distance2 : min
)
}
}
It might very well be that the cost of using lazy var
here outweighs the potential duplicated calls to min(_:_:)
and max(_:_:)
, since these are not the most computationally heavy calculations. But in cases where the calculative cost matters, local lazy var
iables would be incredibly useful.
Re: workarounds. Closures and func
tion wrappers will only work if the var
iable it's wrapping is only used once. Breaking the var
iable out into the namespace above it, pollutes it and is considered bad practice. A lazy struct
wrapper is the most elegant hack, but has extra cognitive overhead.
This should be in the language.