[squeak-dev] Error in Promises/A+ reject implementation?

Jakob Reschke forums.jakob at resfarm.de
Sat Apr 4 22:00:35 UTC 2020


Hello all,

I think our Promise behaves wrong, but I would like a second opinion.
We have this test case:

    testifRejectedRunsBlockIfPromiseFails
        | p q error |
        error := nil.
        p := Promise new.
        q := p ifRejected: [:e | error := e].
        p rejectWith: KeyNotFound new.
        self assert: q isRejected.
        self assert: KeyNotFound equals: error class.

But the JavaScript behavior is actually different:

    x = {};
    p = Promise.reject("Rejected");
    q = p.then(null, error => error);
    q.then(value => { x.value = value; }, error => { x.error = error });
    x // <- { value: "Rejected" }

The difference: the chained promise q is resolved instead of rejected.
Otherwise x would look like this: { error: "Rejected" }.

I think the behavior in our Promise is also in violation with the
Promises/A+ specification it claims to implement
(https://promisesaplus.com/):

[...]
2.2.7 then must return a promise.

    promise2 = promise1.then(onFulfilled, onRejected);

2.2.7.1 If either onFulfilled or onRejected returns a value x, run the
Promise Resolution Procedure [[Resolve]](promise2, x).

2.2.7.2 If either onFulfilled or onRejected throws an exception e,
promise2 must be rejected with e as the reason.
[...]

So if I understand this correctly, since in the test case Promise p
gets rejected and the ifRejected: block evaluates to e without being
curtailed by an exception, Promise q should be resolved, not rejected,
with e, according to ยง2.2.7.1.

Do you agree and should we fix this?


On an only slightly related note, I am unhappy that I cannot debug
errors in promise handler blocks (then: [...] ifRejected: [...]). It
catches all those errors and just rejects the promise. In a server
environment that would probably be ok, but at development time at
least I want to have the chance to investigate the problem in a
debugger. Especially those programmer's errors resulting in
MessageNotUnderstood, which I could fix on the fly and let the program
proceed. In JavaScript you cannot resume exceptions, but in Smalltalk
you can. It might be nice to turn the on: Error do: [:e | p
rejectWith: e] code in Promise into an ifCurtailed: [p rejectWith: e]
to allow exceptions/errors to be resumed before rejecting the promise.
The promise would still be rejected if you press Abandon in the
debugger. Problem: further errors in the rejected handlers would
result in "Unwind error during termination". This could in turn be
avoided by rejecting the promise in the "future", that is the next
cycle of the world. Opinions?

Kind regards,
Jakob


More information about the Squeak-dev mailing list