rethrows
lets you specify that a function can only throw if one of the functions passed to it as a parameter can throw. It enforces this by only allowing try
to be applied to calls to those functions or rethrows
functions which are being passed those functions, and only allowing throws
inside a catch
block.
However, this enforcement can sometimes get in the way. For example, this function only throws if the function it is passed throws, but the compiler cannot statically prove this to itself:
function someOperation<R>(do body: () -> throws R) -> rethrows R {
var result: R?
var error: Error?
// __someOperation is a version of the operation which doesn't support
// returning a value or throwing. This happens a lot when you're
// wrapping Objective-C.
__someOperation {
do { result = try body() }
catch let e { error = e }
}
if let error = error { throw error }
return result!
}
It is possible to work around this by exploiting certain bugs in the rethrows
checking—the Dispatch
overlay does this to add error handling to DispatchQueue.sync(execute:)
—but this is not ideal for obvious reasons.
I propose that we add a rethrows(unchecked)
variant of the keyword which says that the function promises it will only throw if one of the throws
functions passed to it actually throw, but disables the compile-time checking of the function body. This would allow us to cleanly write wrappers like this one.
An alternative might be to build an equivalent to withoutActuallyEscaping(_:do:)
, but I can't come up with a good name for it (withoutActuallyThrowingUnlessRethrowing(from:do:)
?), and I think I had trouble prototyping such a thing when I tried a couple of weeks ago.
I can't work on this immediately, but I wanted to see if people were interested in this and what our preferred design would be if we had it.