I assume what you're trying to do is lazily generate the default for a writable property. I often find that people jump to laziness when it isn't needed. Make sure this is really worth the trouble. This would only be worth it if the default value is rarely used, but fairly expensive to create. But if that's your situation, this is one way to do it.
lazy
implements one very specific and fairly limited pattern that often is not what you want. (It's not clear at all that lazy
was a valuable addition to the language given how it works, and there is active work in replacing it with a much more powerful and useful system of attributes.) When lazy
isn't the tool you want, you just build your own. In your example, it would look like this:
private var _pi: Double?
var pi: Double {
get {
if let pi = _pi { return pi }
let result = // calculations....
_pi = result
return result
}
set { _pi = newValue }
}
This said, in most of the cases I've seen this come up, it's better to use a default value in init:
func computePi() -> Double {
// compute and return value
}
// This is global. Globals are lazy (in a thread-safe way) automatically.
let computedPi = computePi()
struct X {
let pi: Double // I'm assuming it was var only because it might be overridden
init(pi: Double = computedPi) {
self.pi = pi
}
}
Doing it this way only computes pi once in the whole program (rather than once per instance). And it lets us make pi
"write-exactly-once" rather than mutable state. (That may or may not match your needs; if it really needs to be writable, then var
.)
A similar default value approach can be used for objects that are expensive to construct (rather than static things that are expensive to compute) without needing a global.
struct X {
let pi: Double
init(pi: ExpensiveObject = ExpensiveObject()) {
self.pi = pi
}
}
But sometimes getters and setters are a better fit.