Got a fail-able initializer, i.e. init?
.
Want to add a throwable one, for Decodable
.
When you have a fail-able initializer, and use it in a sibling initializer call, you can use !
to crash the program if the second initializer is not failable, or leave no suffix if the second initializer is also failable, to propagate the fail-ness. But what if you want the second initializer to be nonfailable and convert the fact that the first initializer returned nil
with a custom Error
, or otherwise eat the error?
I didn't see any example in the Swift guide that covers this. And my naïve attempt to assign the result of self.init
to a variable so I can check if it's nil
didn't work. The error was:
Initializer delegation ('self.init') cannot be nested in another statement
Hmm...
Here's an awkward workaround:
extension RingBuffer: Decodable where Element: Decodable {
public init(from decoder: Decoder) throws {
let values = try decoder.singleValueContainer()
guard let self0 = RingBuffer(try values.decode(type(of: elements))) else { throw DecodingError.dataCorruptedError(in: values, debugDescription: "Elements was unexpectedly empty") }
self = self0
}
}
Was this the imagined resolution for this case, or did the planners of the initializer feature straight up forget this combination? (I'm feeling the latter.) Has anyone done a bug on this? (A quick look didn't find anything.) But, I can't think of a syntax that wouldn't be only slightly less awkward:
extension RingBuffer: Decodable where Element: Decodable {
public init(from decoder: Decoder) throws {
self.init(try values.decode(type(of: elements))) ?? throw DecodingError.dataCorruptedError(in: values, debugDescription: "Elements was unexpectedly empty")
}
}
I guess a bug name could be: "An initializer that delegates to a failable initializer has no way to check if the inner call failed."