Description
To quickly recap the previous discussion:
I asked if there should be a catch
or recoverWith
method along the lines of:
extension Result {
func catch(transform: NSError -> Result<T>) -> Result<T> {
switch self {
case Success(let value): return .Success(value)
case Failure(let error): return transform(error)
}
}
}
@rnapier responded thusly:
catch looks very similar to recoverWith() that I've been playing with based on recover() from Scala Futures.
The problem I ran into it in this formulation is that it can be be overly aggressive. Consider:
let x = something() .flatMap(more) .flatMap(commonFailer) .catch(recoveryFunc) .flatMap(evenMore)The problem I kept bumping into is that I meant recoveryFunc to apply to commonFailer, but it necessarily applies to everything up to that point. I found that injected surprising bugs because errors from something() were ignored in a spooky-action-at-a-distance kind of way.
I've been exploring a tighter binding like this:
let x = something() .flatMap(more) .recoverWith(recoveryFunc, commonFailer) .flatMap(evenMore)As a real-world example from my code (in this iteration I was calling it rescueWith, which might also be a fine name):
return apiResultP(url) { $0 |> asJSON >>== asJSONDictionary >>== forKey("query") >>== asJSONDictionary >>== forKey("pages") >>== asJSONDictionary >>== forKey(toString(page.identifier)) >>== asJSONDictionary >>== rescueWith([], { forKey("images") >>== asJSONArray }) >>== forEach { $0 |> asJSONDictionary >>== forKey("title") >>== asString <**> { (page, $0) } } } }My old catch-style code quietly ignored network errors, which I didn't realize was happening until I built more negative tests.