<div dir="ltr">Hi Tony,<div class="gmail_extra"><br><div class="gmail_quote">On Wed, Jan 31, 2018 at 3:37 PM,  <span dir="ltr"><<a href="mailto:commits@source.squeak.org" target="_blank">commits@source.squeak.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">A new version of Kernel was added to project The Inbox:<br>
<a href="http://source.squeak.org/inbox/Kernel-tonyg.1148.mcz" rel="noreferrer" target="_blank">http://source.squeak.org/<wbr>inbox/Kernel-tonyg.1148.mcz</a><br>
<br>
==================== Summary ====================<br>
<br>
Name: Kernel-tonyg.1148<br>
Author: tonyg<br>
Time: 31 January 2018, 11:37:21.27021 pm<br>
UUID: 2a675301-406b-4222-9599-<wbr>84358a7cc506<br>
Ancestors: Kernel-eem.1147<br>
<br>
Brings the Promise implementation closer to Javascript/A+ promises in two ways:<br>
        * Resolving a Promise with another Promise causes them to be chained together<br>
        * Resolving or Rejecting a Promise that is not pending is a no-op, like the Firefox/Chrome/etc in-browser promise implementations.<br>
The tests have been changed in KernelTests-tonyg.331 accordingly.<br>
<br>
=============== Diff against Kernel-eem.1147 ===============<br>
<br>
Item was changed:<br>
  Object subclass: #Promise<br>
+       instanceVariableNames: 'value resolvers mutex state error rejecters'<br>
-       instanceVariableNames: 'onError value resolvers mutex state error rejectors rejecters'<br>
        classVariableNames: ''<br>
        poolDictionaries: ''<br>
        category: 'Kernel-Processes'!<br>
<br>
+ !Promise commentStamp: 'tonyg 1/31/2018 23:34' prior: 0!<br>
- !Promise commentStamp: 'fbs 5/17/2013 18:23' prior: 0!<br>
  I represent the result of an asynchronous message.  Once the message is processed, I will be resolved to a value.  I am typically instantiated by invocations of #futureSend:at:args: (and not by #futureDo:atArgs:).<br>
<br>
  See class-comment of FutureNode.<br>
<br>
  I also implement the Promises/A+ Javascript specification. This allows you to chain my instances to perform arbitrarily complex asynchronous tasks with error handling baked in.<br>
<br>
+ A Promise may be in one of three possible states: #pending, #fulfilled or #rejected. A Promise may move from #pending -> #fulfilled (by way of the resolveWith: message), or from #pending -> #rejected (by way of rejectWith:). No other state changes may occur.<br>
+<br>
+ Once #fulfilled or #rejected, a Promise's value must not change. In keeping with the major Javascript Promise implementations' interpretations of this, calls to resolveWith: or rejectWith: when a Promise is in #fulfilled or #rejected state are simply ignored - an error is not signalled. (See test cases PromiseTest testFirstResolutionWins, testCannotRejectFulfilledPromi<wbr>se and testCannotResolveaRejectedProm<wbr>ise.)!<br>
- A Promise may be in one of three possible states: #pending, #fulfilled or #rejected. A Promise may move from #pending -> #fulfilled, or from #pending -> #rejected. No other state changes may occur. Once #fulfilled or #rejected, a Promise's value must change.!<br>
<br>
Item was changed:<br>
  ----- Method: Promise>>rejectWith: (in category 'resolving') -----<br>
  rejectWith: anObject<br>
        "Reject this promise."<br>
        mutex critical: [<br>
+               (state == #pending) ifTrue: [<br>
+                       error := anObject.<br>
+                       state := #rejected.<br>
+                       rejecters do: [:r | self evaluateRejecter: r]]]!<br>
-               (state == #fulfilled) ifTrue: [self error: 'Promise was already resolved'].<br>
-               (state == #rejected) ifTrue: [self error: 'Promise was already rejected'].<br>
-               error := anObject.<br>
-               state := #rejected.<br>
-               rejecters do: [:r | self evaluateRejecter: r]].!<br>
<br>
Item was changed:<br>
  ----- Method: Promise>>resolveWith: (in category 'resolving') -----<br>
  resolveWith: arg<br>
+       "Resolve this promise. If arg is itself a Promise, make this promise depend upon it,<br>
+       as detailed in the Promises/A+ spec:<br>
+               <a href="https://promisesaplus.com/#the-promise-resolution-procedure" rel="noreferrer" target="_blank">https://promisesaplus.com/#<wbr>the-promise-resolution-<wbr>procedure</a>"<br>
+<br>
+       (arg isKindOf: Promise)<br></blockquote><div><br></div><div>I'd /much/ rather see Object>>isPromise and Promise>>isPromise than this.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+               ifTrue: [<br>
+                       arg whenResolved: [:v | self resolveWith: v].<br>
+                       arg whenRejected: [:e | self rejectWith: e]]<br>
+               ifFalse: [<br>
+                       mutex critical: [<br>
+                               (state == #pending) ifTrue: [<br>
+                                       value := arg.<br>
+                                       state := #fulfilled.<br>
+                                       resolvers do: [:r | self evaluateResolver: r]]]]!<br>
-       "Resolve this promise"<br>
-       mutex critical: [<br>
-               (state == #fulfilled) ifTrue: [self error: 'Promise was already resolved'].<br>
-               (state == #rejected) ifTrue: [self error: 'Promise was already resolved'].<br>
-               value := arg.<br>
-               state := #fulfilled.<br>
-               resolvers do: [:r |<br>
-                       self evaluateResolver: r]].!<br>
<br>
Item was changed:<br>
  ----- Method: Promise>>then: (in category 'monad') -----<br>
  then: resolvedBlock<br>
+       ^ self then: resolvedBlock ifRejected: [:e | "Pass rejection reason along" e].!<br>
-       ^ self then: resolvedBlock ifRejected: [:ignored | "Do nothing"].!<br>
</blockquote></div><br><br><div class="gmail_signature" data-smartmail="gmail_signature"><div dir="ltr"><div><span style="font-size:small;border-collapse:separate"><div>_,,,^..^,,,_<br></div><div>best, Eliot</div></span></div></div></div>
</div></div>