Reputation: 1650
Please take a look at the following code:
class A {
let a: String
let b: String
init(a: String, b: String) {
self.a = a
self.b = b
}
}
class B: A {
let c: Bool
private let aExpectedValue = "a"
private let bExpectedValue = "b"
override init(a: String, b: String) {
c = (a == aExpectedValue && b == bExpectedValue)
super.init(a: a, b: b)
}
}
This causes an error in B.init
:
However, if I change it either to c = (a == aExpectedValue)
or c = (b == bExpectedValue)
then it compiles correctly.
Does anybody know why is that?
Upvotes: 6
Views: 1588
Reputation: 299295
The problem is in bExpectedValue
. That's an instance property on B
. That interacts with the definition of &&
on Bool:
static func && (lhs: Bool, rhs: @autoclosure () throws -> Bool) rethrows -> Bool
The @autoclosure
makes the b == bExpectedValue
into a closure, capturing it as self.bExpectedValue
. That's not allowed before initialization is complete. (The closure here is to allow short-circuiting. The rhs closure is not evaluated if lhs is false.)
This is pretty awkward (see SR-944 that MartinR references for a little discussion about it).
If bExpectedValue
were static
, or if it were moved outside the class definition, then this wouldn't be an issue. The following approach will also fix it:
override init(a: String, b: String) {
let goodA = a == aExpectedValue
let goodB = b == bExpectedValue
c = goodA && goodB
super.init(a: a, b: b)
}
Upvotes: 15
Reputation: 1818
You need to create a new initializer with another vars or call super.init(a:, b:) before any expression with this properties.
Call this:
override init(a: String, b: String) {
super.init(a: a, b: b)
c = (a == aExpectedValue && b == bExpectedValue)
}
or change it to:
init(newA: String, newB: String) {
c = (newA == aExpectedValue && newB == bExpectedValue)
super.init(a: newA, b: newB)
}
Upvotes: 0