New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to switch catches on error types? #62
Comments
Yeah so it seems like there are two issues here: First, you want to be able to catch only uncaught errors. While we can write code that handles this pretty easily, I think it does represent a conceptual problem. Any time you filter out certain errors from being handled within a catch block, you run the risk of errors being accidentally filtered out and causing silent bugs. For example, twice now I've run into the issue with PromiseKit where it silently filters out cancellation errors from catch blocks causing bugs. You could imagine a situation where you have this function in a library:
and then a consumer comes along and calls this code:
What errors should be yielded here? They don't know that AirTrafficErrors have already been caught, and they might want to know about them anyway. So then you end up with a situation where you want to disambiguate with names, such as You could also address it by passing a second block to It's a real problem and it almost makes me wish I hadn't added the matchers to the library. The second issue is that you'd like a recover method that only recovers errors matching a certain type, and as far as I can tell, this is a slam dunk. If you want to make a PR with support for that function, I'd be happy to review and integrate it! |
I'm going to give this a shot! |
Closing this issue in favor of #63. |
I've been thinking about this more, and I think we can manage it without too much more complexity by adding a new case to the state enum called |
Interesting idea. I like the explicit wording of For my project, I went a somewhat different direction and added a I do like the resulting declarations you can make. Here's an example from my tests: AirTrafficClient()
.suggestions("ea", for: .departure)
.then { _ in fail("should have gone into the silencing-block") }
.silence(type: AirTrafficError.self) { expect($0.errorStatusCode) == 400 }
.catch { fail($0.localizedDescription) }
.always { done() } Unfortunately my approach can't handle already-optional input type, and would turn it into double-optional /**
Allows you to silence/squelch/eat Promise-errors of a particular type, and turn the original Promise.Value
into an optional one. Due to this last implementation detail, this extension will unfortunately not work
for Promises that already define an optional return type.
*/
public extension Promise {
func silence<E: Error>(type errorType: E.Type, _ silencing: ((E) throws -> Void)? = nil) -> Promise<Value?> {
let anyType: Any.Type = Value.self
if anyType is OptionalMarker.Type {
fatalError("this method should not be used with optional Promise-values")
}
return Promise<Value?> { fulfill, reject in
self.then(fulfill)
.catch { anyError in
guard let error = anyError as? E else {
reject(anyError)
return
}
do {
try silencing?(error)
fulfill(nil)
} catch let error {
reject(error)
}
}
}
}
}
private protocol OptionalMarker: ExpressibleByNilLiteral {}
extension Optional: OptionalMarker {} |
For this particular use case, what I would actually do is instead of using optionals, you could map to another type that's shaped like an optional but isn't one, and then just use recover. So you'd do
And then you can map to this new result type and just use recover
Would that work for your use case? |
It actually would. It would also alleviate the need to explain what a |
Would the compiler accept a more |
Yeah, it seems like it should be possible, but you'd probably want it to be a throwing function so you can have an error escape hatch. Worth trying! |
Thanks for writing #58, that's a nice feature, thanks!
I was looking for a way to mimick a switch-like decision tree with these error types. But from the looks of the current implementation, consecutive catch blocks will all be called when the promise is rejected:
There also seems to be no error-type based
recover
-method that would allow me to catch (and squelch) errors of a specific type, so if I want to be "picky" about specific error types, I still have to write the decision tree within the catch block, instead of leveraging the Promise API.How would you approach something like this?
Cheers,
Eric-Paul
The text was updated successfully, but these errors were encountered: