I've filed a bug for this here, but I also wanted to consult the Evolution forums since it doesn't seem to be something that is actually wrong with the compiler--the error makes perfect sense as long as you understand @autoclosure.
In brief, the code:
struct Test {
var prop1: Bool
var prop2: Bool
init() {
self.prop2 = false
self.prop1 = true && self.prop2
}
}
results in an error on the second line of the initializer:
error: MyPlayground.playground:1:30: error: variable 'self.prop1' captured by a closure before being initialized
self.prop1 = true && self.prop2
^
because the self.prop2 expression is turned into an autoclosure, forcing the capture of self. Is this the desired behavior? It seems wildly confusing to be unable to use self.prop2 in a logical operator here.
The wording of the error is confusing, but since you normally can't use self before you finish initializing all the properties, I would not be surprised to see an error there. I just think the error should be more helpfully worded.
so it doesn't seem to be an issue with the usage of self. It should be easy for the compiler to determine which properties of self have definitely been initialized so far.
The issue isn't even necessarily a usage of self before all properties are initialized, because this is totally valid:
struct Test {
var prop1: Int
var prop2: Int
init() {
self.prop2 = 5
// The compiler is fine with self.prop2 being used before
// self.prop1 is initialized
self.prop1 = 20 - self.prop2
}
}
So the closure is the point of failure here.
Since && is marked as both @_transparent and @inline(__always), doesn't the compiler have enough knowledge that self isn't "really" being captured in the original post?
I think the surprise here might be that && appears not to be a special case in the compiler, but just a normal operator which could be defined by any Swift coder in one of his programs.
Imho that's a good thing, but it would probably be less confusing to have a more vague message like "self used before fully initialized":
It's easy to explain why && tries to avoid evaluation of the second expression, it's easy to explain that this behavior is achieved with a closure - but it would still be an extremely verbose error message...
@Tino Any Swift coder can trivially define the && operator by using the @autoclosure attribute--many Swift programmers are just unaware that it exists.
@allevato Right, it should be pretty apparent to the compiler, because once inlined we'd end up with self.prop1 = false ? try { self.prop2 }() : false which the compiler should be able to figure out needn't capture all of self at all. According to @Joe_Groff on the bug thread, this worked in an older iteration of the compiler when this inlining happened before the definite initialization check, but now that check happens before the inlining occurs.