Reputation: 2952
In a following class
class Foo {
let _defaultValue = "N/A"
let value: String
init (dict: NSDictionary) {
self.value = dict["bar"] as? String! ?? _defaultValue
}
}
compiler fails with the message
constant 'self.value' captured by a closure before being initialized
As far as I can see, no operators read `self.value. The message seems somewhat confusing.
I accidentally came up with a workaround. I should say it confuses me even more:
class Foo {
let value: String
init (dict: NSDictionary) {
let _defaultValue = "N/A"
self.value = dict["bar"] as? String! ?? _defaultValue
}
}
Declaring _defaultValue
and initializing it within the constructor makes the code compile.
It'd be an immense help if someone could explain why an error occurs in the first case and what is the compiler happier in the second case?
Upvotes: 9
Views: 4564
Reputation: 539755
The reason for the error message is that the nil-coalescing operator is defined as
public func ??<T>(optional: T?, defaultValue: @autoclosure () throws -> T) rethrows -> T
and does a "auto closure" on the second argument (in order to get a short-circuiting behaviour). So
self.value = dict["bar"] as? String ?? _defaultValue
is transformed by the compiler to
self.value = dict["bar"] as? String ?? { self._defaultValue }()
and here the compiler complains because self
is captured before
being fully initialised. (The error messages are slightly different
between Swift 2 and Swift 3).
Possible workarounds. You can assign the property to a local variable first:
init(dict: NSDictionary){
let defValue = _defaultValue
self.value = dict["bar"] as? String! ?? defValue
}
Or you can make it a static property of the class:
class Foo {
static let _defaultValue = "N/A"
let value: String
init(dict: NSDictionary) {
self.value = dict["bar"] as? String ?? Foo._defaultValue
}
}
Or replace ??
by an if-statement:
class Foo {
let _defaultValue = "N/A"
let value: String
init (dict: NSDictionary) {
if let value = dict["bar"] as? String {
self.value = value
} else {
self.value = _defaultValue
}
}
}
Addendum: Related resources:
Quote from the bug report:
Jordan Rose: This is true since && is implemented using @autoclosure, but it's certainly suboptimal.
Upvotes: 21