[squeak-dev] The Inbox: KernelTests-jr.383.mcz

Chris Muller ma.chris.m at gmail.com
Tue Jun 30 03:18:38 UTC 2020

Hi Jakob,

Sorry for the delayed reply.  So many things right now!

I was sometimes confused about this too: future itself does not return
> a Promise, but future + the following message send does. This is due
> to the compiler transformation explained in FutureNode. So value will
> not be sent to the Promise and p will hold the Promise right away and
> not be nil.

Ah!  Sorry, you're right.  So "value" there is just to satisfy the
compiler.  I guess the #future magic-trick kinda worked against its own
"readability" in that specific case, huh?..  :)  (#yourself would be better
form there, IMO).

> So, I agree that #future is confusing, but it is also much less to
> read than p := Promise new. Project current addDeferredUIMessage:
> [[... p resolveWith: ...] ifCurtailed: "or whatever we settle on" [p
> reject]].

#future also breaks the formatter, which I use constantly and, since it has
to assume the receiver might be a Morph, has to go through Project current
addDeferredUIMessage:, MUCH slower than basic process #fork'ing, which is
all I needed.

> I don't think you ever could use Promises and values interchangeably.
> Promise>>wait does more or less what you want, but it means you have
> to use the promise explicitly, not interchangeably. You can chain
> promises with then:[ifRejected:], and consume the Promise outcome in
> the respective block argument, turning your control flow from
> left-to-right-top-to-down into Promise style... But just getting the
> value of the Promise at some point without wait might just answer nil
> if still unresolved.

It essentially renders its #value message completely and utterly useless,
since you can't discern between whether nil was the result or simply still
running, without checking one of the state messages but... why?

That's why I overrode Promise>>#value to:

    ^ self wait

Interchangeability via #value also means that chaining "just works".  My
code can always simply resolveWith: a value or a Promise of a value, and if
its a Promise, the existing code chains it for me, without ever having to
bring the #then: API into my code.

> About signalling errors upon #value as you put it: you mean you want
> to get the original Exception when you get the result of the promise,
> so you don't have to check in which state the promise is? It sounds
> useful at first, but the result or reason (for errors) can be
> retrieved more than once; would the exception only be signalled
> (again) upon the first retrieval of the result?

Yes.  And your program's error-handling can worry about its own errors
only, not having to account for BrokenPromise..

> Also it would look
> funny in the Debugger stack: either you put the original stack of the
> exception on top of the current (result getting) one, or you hide the
> current stack, or you cut away the sender of the exception context
> (which makes it less useful). Do you have an idea how to resolve this?

I think you can get the original stack from the error that's signaled.  I'd
welcome a better multiprocess debugging tool, for sure, it can be difficult
to figure out when things don't go as expected.

> Also note that you can reject a promise with something else than an
> Exception. It could also be some kind of error value or just a string
> that explains the rejection.

Yes, but I don't use it that way, because I prefer the interchangeability.
Honestly, it brings all kinds of case-logic into the clients code.

> You would not be able to distinguish that
> from a regular result without type checking.

Current Promise doesn't even have a way to ask #isPending, you always  have
to check *both* terminal states (#isResolved, #isRejected) usually with a
"not" in there.  Ugh.

> Maybe we could have a
> specialized promise that only rejects on exceptions and would allow
> the kind of workflow you seem to have in mind where the promise is
> like a proxy for the result. If we determine that it is useful. :-)

I did subclass Promise in the GraphQL framework to do just that and, it
worked beautifully.  Took me quite a bit of mind-wrangling to finally
arrive at this simplicity, all the extra stuff I didn't need really took me
on a mental ride around the barnyard just to figure out I didn't need it.

During that ride, I did notice a minor inefficiency in Promise>>#wait --
for already-resolved Promises, it could simply check isResolved before
going through the Semaphore.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20200629/b626dcae/attachment.html>

More information about the Squeak-dev mailing list