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

promise.fulfill rejects the promise #140

Closed ben-z closed 4 years ago

ben-z commented 4 years ago

I'm encountering a behaviour where calling promise.fulfill with an Error argument results in the promise being rejected:

struct SomeError: Error {}

let promise = Promise<Error?>.pending()
promise.then {_ in
    print("Promise fulfilled")
}.catch {_ in
    print("Promise rejected")
}

promise.fulfill(SomeError())

The resulting output is Promise rejected instead of Promise fulfilled. Is this expected behaviour?

It appears that fulfill and reject are not distinguished on the objc layer: https://github.com/google/promises/blob/7373adec497aaf3e18fe0b9c11a39e7b8c1b5337/Sources/Promises/Promise.swift#L57-L64

shoumikhin commented 4 years ago

Hi Ben,

Yes, that's made deliberately, so that a promise cannot be fulfilled with an error, but only rejected.

Thanks.

ben-z commented 4 years ago

Hi @shoumikhin,

Thanks for the quick reply! Any idea why this decision was made deliberately? Coming from a Javascript background I was expecting promise.fulfill to fulfill the promise regardless of what's passed in.

Thanks

shoumikhin commented 4 years ago

Actually, I'd be curious to learn why JS promises allow fulfilling with errors. Perhaps, because JS is an untyped language and it's not feasible to distinguish between errors and everything else? Or maybe there're real use cases when you want a promise fulfilled with an error? Don't know. It just seems right to treat a promise resolved with an error as rejected.

ben-z commented 4 years ago

That's a very good question that I don't have an answer for 😄. Interesting that it never occurred to me before. I think a use case for fulfilling with an error may occur when we are want a function that asynchronously returns an error object (for passing to other parts of the application):

let errObj: CustomError? = try? await(getErrorObj())
// use errObj elsewhere

or is this just bad programming?

Anyway, the purpose of this issue is fulfilled. I'll close it now.

jjc235 commented 2 years ago

By the way, this prevents extending a type (i.e. String) to conform to Error- a fulfilled promise with a String return value would be kicked into being rejected.