In following code example:
class Foo {
private let queue = DispatchQueue(label: "foo.queue")
enum Error: Swift.Error {
case unknown
}
func throwError() throws {
throw Foo.Error.unknown
}
}
Normally, if you call a throwable function along with a closure which throws as well in a rethrow function, like the following extension, a complier error will prompt saying
a function declared 'rethrows' may only throw if its parameter does
extension Foo {
func withErrorThrown<ExecutionResult>(execute: () throws -> ExecutionResult) rethrows -> ExecutionResult {
try throwError() // Error: Call can throw, but the error is not handled; a function declared 'rethrows' may only throw if its parameter does
return try execute()
}
}
However, if you wrap them in a sync
function from an instance of a DispatchQueue
, the prompt goes away and compiles fine:
extension Foo {
func withErrorThrown<ExecutionResult>(execute: () throws -> ExecutionResult) rethrows -> ExecutionResult {
return try self.queue.sync {
try throwError()
return try execute()
}
}
}
And you can call it without try
(because it only rethrows) and the error skips handling and causes crash:
let string = Foo().withErrorThrown(execute: { "" })
/// Compiles fine
But the code will crash with error when runs:
error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
The process has been left at the point where it was interrupted, use "thread return -x" to return to the state before expression evaluation.
I am aware that this is wrong implementation with the rethrows
, the correct one should be to change rethrows
to throws
, because a throwable function always gets called in this case.
But I think this kind of implementation should at least generate a warning like the first extension.