google / promises

Promises is a modern framework that provides a synchronization construct for Swift and Objective-C.
Apache License 2.0
3.79k stars 292 forks source link

How to rethrow error from .catch() ? #171

Closed tkafka closed 3 years ago

tkafka commented 3 years ago

I have a function that calls a promise, processes the result (in .then), logs error (in .catch), but I would still like to return either fulfilled or rejected promise (so that caller knows if the call succeeded).

However, I can't find how to rethrow the error - I tried this, but Swift tells me that Declared closure result 'Error' is incompatible with contextual type 'Void':

.catch(on: .main) { error -> Error in
    log(error.localizedDescription)
    return error
}

Similarly, when I try to rethrow the error, I get Invalid conversion from throwing function of type '(Error) throws -> Void' to non-throwing function type '(Error) -> Void':

.catch(on: .main) { error -> Error in
    log(error.localizedDescription)
    throw error
}

The whole code:

func doSomething() -> Promise<Bool> {
    syncStuff() // returns Promise<Bool>
        .then(on: .main) { didSync -> Bool in
            log(didSync ? "Synced some items" : "No items needed syncing")
            return didSync
        }
        // this doesn't compile
        .catch(on: .main) { error -> Error in
            log("Error syncing items: \(error.localizedDescription)")
            return error
        }
        // this doesn't compile either
        .catch(on: .main) { error in
            log("Error syncing items: \(error.localizedDescription)")
            throw error
        }
}
jeff-h commented 3 years ago

Have you looked at recover? You should be able to pass the original error onwards like so:

.recover { error in
    // Log error here.
    return Promise(error)
}
tkafka commented 3 years ago

@jeff-h Aha, thank you! I am reading the spec closely now, and it seems that my expectations were wrong - catch actually 'rethrows' automatically (so that the .then after it doesn't run):

catch operator expects one argument - a block, which has the error that the promise was rejected with as an argument. The operator itself implicitly returns another promise, that is rejected with the same error.

I came from javascript world, where Promise's catch actually behaves like recover, so I expected this to apply everywhere. Apparently, these semantics varies across languages.

Screen Shot 2021-04-29 at 14 18 14