I'm curious about solutions to another rethrows problem: building higher-order functions/methods that can accept re-throwing functions.
Here's an example that doesn't work:
extension Optional {
public func apply<A>(_ f: ((Wrapped) -> A)?) -> A? {
return f.flatMap(self.map)
}
}
The compiler error:
Call can throw, but it is not marked with 'try' and the error is not handled
It's understandable, but unfortunate. We're passing non-throwing f along and even though nothing throwing is in scope, Swift can't figure it out.
How about a more complicated example? Here's a zip that flattens certain pyramids of death:
func zip<A, B, R>(
_ f: @escaping ((A) throws -> R) throws -> R,
_ g: @escaping ((B) throws -> R) throws -> R,
with: (A, B) -> R
) throws -> R {
return try f { a in
try g { b in
with(a, b)
}
}
}
We have to promote rethrows to throws for another compiler error:
Only function declarations may be marked 'rethrows'; did you mean 'throws'?
An example (toy) use, which unfortunately requires do/try if we can't address throws/rethrows:
func someCFunction(_ x: UnsafeRawBufferPointer, _ y: UnsafeRawBufferPointer) -> Int {
return 1
}
let xs = [1, 2]
let ys = [3, 4]
try zip(xs.withUnsafeBytes, ys.withUnsafeBytes, with: someCFunction)
It'd be nice to have an escape hatch for library authors to compose rethrows more generally.