Consider this code:
class Foo {
var a: Int
var b: Int
init(a: Int, b: String?) throws {
self.a = a
guard self.a > 0 else {
throw "Too little a!"
}
self.b = self.a
}
}
extension String: Error {}
Pretty non-sensical, but the point is that it compiles fine. Now replace the guard with:
guard b == nil || self.a > 0 else {
Not we get a compiler error!
Error: 'self' captured by a closure before all members were initialized
I for one don't see a closure anywhere. Is the compiler translating guard conditions into closures if they are compound expressions, thus introducing the error (which would be correct if there was a closure)?
Bug or feature?
This is with Swift 3.0.2.
The problem, as explained by Martin in this Q&A, is that the
||operator is implemented with an@autoclosuresecond parameter, in order to allow for short-circuit evaluation (the right hand expression need only be evaluated if the left hand expression evaluates tofalse).Therefore in the expression
self.a > 0is implicitly wrapped in a() -> Boolclosure. This is problematic, because it requires the capture ofself, so thatacan be accessed upon applying the closure.However, in an initialiser, Swift tightly restricts what you can do with
selfbefore it has been fully initialised. One of these restrictions is the inability to be captured by a closure – which is why you get a compiler error.Although really, there's nothing wrong with the closure
{ self.a > 0 }capturingselfbefore it's fully initialised, because all the closure is doing is accessingaon it, which has already been initialised. Therefore, this is really just an edge case (for which there's an open bug report), which I hope will be smoothed out in a future version of the language.Until then, one solution as shown by Martin in this Q&A, is to use a temporary local variable to create a copy of the value of
self.a, avoiding the capturing ofselfin the closure:Obviously, this assumes that
self.a != a, otherwise you can just refer toainstead ofself.ain theguardcondition.