google/promises

promise.fulfill rejects the promise

ben-z opened this issue · 5 comments

ben-z commented

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:

public func fulfill(_ resolution: Value) {
objCPromise.__fulfill(Promise<Value>.asAnyObject(resolution))
}
/// Rejects `self` with the given `error`.
public func reject(_ error: Error) {
objCPromise.__fulfill(error as NSError)
}

Hi Ben,

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

Thanks.

ben-z commented

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

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

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.

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.