The Inbox: Kernel-tonyg.1148.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

The Inbox: Kernel-tonyg.1148.mcz

commits-2
A new version of Kernel was added to project The Inbox:
http://source.squeak.org/inbox/Kernel-tonyg.1148.mcz

==================== Summary ====================

Name: Kernel-tonyg.1148
Author: tonyg
Time: 31 January 2018, 11:37:21.27021 pm
UUID: 2a675301-406b-4222-9599-84358a7cc506
Ancestors: Kernel-eem.1147

Brings the Promise implementation closer to Javascript/A+ promises in two ways:
        * Resolving a Promise with another Promise causes them to be chained together
        * Resolving or Rejecting a Promise that is not pending is a no-op, like the Firefox/Chrome/etc in-browser promise implementations.
The tests have been changed in KernelTests-tonyg.331 accordingly.

=============== Diff against Kernel-eem.1147 ===============

Item was changed:
  Object subclass: #Promise
+ instanceVariableNames: 'value resolvers mutex state error rejecters'
- instanceVariableNames: 'onError value resolvers mutex state error rejectors rejecters'
  classVariableNames: ''
  poolDictionaries: ''
  category: 'Kernel-Processes'!
 
+ !Promise commentStamp: 'tonyg 1/31/2018 23:34' prior: 0!
- !Promise commentStamp: 'fbs 5/17/2013 18:23' prior: 0!
  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:).
 
  See class-comment of FutureNode.
 
  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.
 
+ 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.
+
+ 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, testCannotRejectFulfilledPromise and testCannotResolveaRejectedPromise.)!
- 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.!

Item was changed:
  ----- Method: Promise>>rejectWith: (in category 'resolving') -----
  rejectWith: anObject
  "Reject this promise."
  mutex critical: [
+ (state == #pending) ifTrue: [
+ error := anObject.
+ state := #rejected.
+ rejecters do: [:r | self evaluateRejecter: r]]]!
- (state == #fulfilled) ifTrue: [self error: 'Promise was already resolved'].
- (state == #rejected) ifTrue: [self error: 'Promise was already rejected'].
- error := anObject.
- state := #rejected.
- rejecters do: [:r | self evaluateRejecter: r]].!

Item was changed:
  ----- Method: Promise>>resolveWith: (in category 'resolving') -----
  resolveWith: arg
+ "Resolve this promise. If arg is itself a Promise, make this promise depend upon it,
+ as detailed in the Promises/A+ spec:
+ https://promisesaplus.com/#the-promise-resolution-procedure"
+
+ (arg isKindOf: Promise)
+ ifTrue: [
+ arg whenResolved: [:v | self resolveWith: v].
+ arg whenRejected: [:e | self rejectWith: e]]
+ ifFalse: [
+ mutex critical: [
+ (state == #pending) ifTrue: [
+ value := arg.
+ state := #fulfilled.
+ resolvers do: [:r | self evaluateResolver: r]]]]!
- "Resolve this promise"
- mutex critical: [
- (state == #fulfilled) ifTrue: [self error: 'Promise was already resolved'].
- (state == #rejected) ifTrue: [self error: 'Promise was already resolved'].
- value := arg.
- state := #fulfilled.
- resolvers do: [:r |
- self evaluateResolver: r]].!

Item was changed:
  ----- Method: Promise>>then: (in category 'monad') -----
  then: resolvedBlock
+ ^ self then: resolvedBlock ifRejected: [:e | "Pass rejection reason along" e].!
- ^ self then: resolvedBlock ifRejected: [:ignored | "Do nothing"].!


Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Kernel-tonyg.1148.mcz

Eliot Miranda-2
Hi Tony,

On Wed, Jan 31, 2018 at 3:37 PM, <[hidden email]> wrote:
A new version of Kernel was added to project The Inbox:
http://source.squeak.org/inbox/Kernel-tonyg.1148.mcz

==================== Summary ====================

Name: Kernel-tonyg.1148
Author: tonyg
Time: 31 January 2018, 11:37:21.27021 pm
UUID: 2a675301-406b-4222-9599-84358a7cc506
Ancestors: Kernel-eem.1147

Brings the Promise implementation closer to Javascript/A+ promises in two ways:
        * Resolving a Promise with another Promise causes them to be chained together
        * Resolving or Rejecting a Promise that is not pending is a no-op, like the Firefox/Chrome/etc in-browser promise implementations.
The tests have been changed in KernelTests-tonyg.331 accordingly.

=============== Diff against Kernel-eem.1147 ===============

Item was changed:
  Object subclass: #Promise
+       instanceVariableNames: 'value resolvers mutex state error rejecters'
-       instanceVariableNames: 'onError value resolvers mutex state error rejectors rejecters'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Kernel-Processes'!

+ !Promise commentStamp: 'tonyg 1/31/2018 23:34' prior: 0!
- !Promise commentStamp: 'fbs 5/17/2013 18:23' prior: 0!
  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:).

  See class-comment of FutureNode.

  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.

+ 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.
+
+ 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, testCannotRejectFulfilledPromise and testCannotResolveaRejectedPromise.)!
- 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.!

Item was changed:
  ----- Method: Promise>>rejectWith: (in category 'resolving') -----
  rejectWith: anObject
        "Reject this promise."
        mutex critical: [
+               (state == #pending) ifTrue: [
+                       error := anObject.
+                       state := #rejected.
+                       rejecters do: [:r | self evaluateRejecter: r]]]!
-               (state == #fulfilled) ifTrue: [self error: 'Promise was already resolved'].
-               (state == #rejected) ifTrue: [self error: 'Promise was already rejected'].
-               error := anObject.
-               state := #rejected.
-               rejecters do: [:r | self evaluateRejecter: r]].!

Item was changed:
  ----- Method: Promise>>resolveWith: (in category 'resolving') -----
  resolveWith: arg
+       "Resolve this promise. If arg is itself a Promise, make this promise depend upon it,
+       as detailed in the Promises/A+ spec:
+               https://promisesaplus.com/#the-promise-resolution-procedure"
+
+       (arg isKindOf: Promise)

I'd /much/ rather see Object>>isPromise and Promise>>isPromise than this.
 
+               ifTrue: [
+                       arg whenResolved: [:v | self resolveWith: v].
+                       arg whenRejected: [:e | self rejectWith: e]]
+               ifFalse: [
+                       mutex critical: [
+                               (state == #pending) ifTrue: [
+                                       value := arg.
+                                       state := #fulfilled.
+                                       resolvers do: [:r | self evaluateResolver: r]]]]!
-       "Resolve this promise"
-       mutex critical: [
-               (state == #fulfilled) ifTrue: [self error: 'Promise was already resolved'].
-               (state == #rejected) ifTrue: [self error: 'Promise was already resolved'].
-               value := arg.
-               state := #fulfilled.
-               resolvers do: [:r |
-                       self evaluateResolver: r]].!

Item was changed:
  ----- Method: Promise>>then: (in category 'monad') -----
  then: resolvedBlock
+       ^ self then: resolvedBlock ifRejected: [:e | "Pass rejection reason along" e].!
-       ^ self then: resolvedBlock ifRejected: [:ignored | "Do nothing"].!


_,,,^..^,,,_
best, Eliot


Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Kernel-tonyg.1148.mcz

Tony Garnock-Jones-5
Hi Eliot,

On 02/01/2018 12:34 AM, Eliot Miranda wrote:
>     +       (arg isKindOf: Promise)
>
> I'd /much/ rather see Object>>isPromise and Promise>>isPromise than this.

Excellent point! Thanks.

There is a Promise>>isPromise, but no matching Object>>isPromise.

Kernel-tonyg.1150 (just committed to Inbox) reintroduces it, and
switches from using isKindOf: to using isPromise.

This change is also in keeping with the spirit of Promises/A+, where
anything that is "thenable" is treated as promise-like.

Tony

Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Kernel-tonyg.1148.mcz

David T. Lewis
Tony has a set of inbox submissions in Kernel, Multilingual, and MultilingualTests
that appear to be ready to move to trunk.

Should we move these to trunk? If no objections I will move them a few days
from now if no one else has gotten to it by then.

There will be some new test failures for UTF8EdgeCaseTest, which is a good
thing since these are new tests that document existing issues.

Dave


On Thu, Feb 01, 2018 at 10:02:22AM +0000, Tony Garnock-Jones wrote:

> Hi Eliot,
>
> On 02/01/2018 12:34 AM, Eliot Miranda wrote:
> >     +?? ?? ?? ??(arg isKindOf: Promise)
> >
> > I'd /much/ rather see Object>>isPromise and Promise>>isPromise than this.
>
> Excellent point! Thanks.
>
> There is a Promise>>isPromise, but no matching Object>>isPromise.
>
> Kernel-tonyg.1150 (just committed to Inbox) reintroduces it, and
> switches from using isKindOf: to using isPromise.
>
> This change is also in keeping with the spirit of Promises/A+, where
> anything that is "thenable" is treated as promise-like.
>
> Tony
>

Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Kernel-tonyg.1148.mcz

marcel.taeumel
In reply to this post by Eliot Miranda-2
+1 for #isPromise

I don't think we need the #isKindOf: "flavor" here because the basic concept seems to be quite mature and thus justifies the addition to the Object protocol.

(For other discussions about #isKindOf: see the history of the mailing list. There was at least one in combination with Morphic Flaps.)

Best,
Marcel

Am 01.02.2018 01:34:33 schrieb Eliot Miranda <[hidden email]>:

Hi Tony,

On Wed, Jan 31, 2018 at 3:37 PM, <[hidden email]> wrote:
A new version of Kernel was added to project The Inbox:
http://source.squeak.org/inbox/Kernel-tonyg.1148.mcz

==================== Summary ====================

Name: Kernel-tonyg.1148
Author: tonyg
Time: 31 January 2018, 11:37:21.27021 pm
UUID: 2a675301-406b-4222-9599-84358a7cc506
Ancestors: Kernel-eem.1147

Brings the Promise implementation closer to Javascript/A+ promises in two ways:
        * Resolving a Promise with another Promise causes them to be chained together
        * Resolving or Rejecting a Promise that is not pending is a no-op, like the Firefox/Chrome/etc in-browser promise implementations.
The tests have been changed in KernelTests-tonyg.331 accordingly.

=============== Diff against Kernel-eem.1147 ===============

Item was changed:
  Object subclass: #Promise
+       instanceVariableNames: 'value resolvers mutex state error rejecters'
-       instanceVariableNames: 'onError value resolvers mutex state error rejectors rejecters'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Kernel-Processes'!

+ !Promise commentStamp: 'tonyg 1/31/2018 23:34' prior: 0!
- !Promise commentStamp: 'fbs 5/17/2013 18:23' prior: 0!
  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:).

  See class-comment of FutureNode.

  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.

+ 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.
+
+ 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, testCannotRejectFulfilledPromise and testCannotResolveaRejectedPromise.)!
- 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.!

Item was changed:
  ----- Method: Promise>>rejectWith: (in category 'resolving') -----
  rejectWith: anObject
        "Reject this promise."
        mutex critical: [
+               (state == #pending) ifTrue: [
+                       error := anObject.
+                       state := #rejected.
+                       rejecters do: [:r | self evaluateRejecter: r]]]!
-               (state == #fulfilled) ifTrue: [self error: 'Promise was already resolved'].
-               (state == #rejected) ifTrue: [self error: 'Promise was already rejected'].
-               error := anObject.
-               state := #rejected.
-               rejecters do: [:r | self evaluateRejecter: r]].!

Item was changed:
  ----- Method: Promise>>resolveWith: (in category 'resolving') -----
  resolveWith: arg
+       "Resolve this promise. If arg is itself a Promise, make this promise depend upon it,
+       as detailed in the Promises/A+ spec:
+               https://promisesaplus.com/#the-promise-resolution-procedure"
+
+       (arg isKindOf: Promise)

I'd /much/ rather see Object>>isPromise and Promise>>isPromise than this.
 
+               ifTrue: [
+                       arg whenResolved: [:v | self resolveWith: v].
+                       arg whenRejected: [:e | self rejectWith: e]]
+               ifFalse: [
+                       mutex critical: [
+                               (state == #pending) ifTrue: [
+                                       value := arg.
+                                       state := #fulfilled.
+                                       resolvers do: [:r | self evaluateResolver: r]]]]!
-       "Resolve this promise"
-       mutex critical: [
-               (state == #fulfilled) ifTrue: [self error: 'Promise was already resolved'].
-               (state == #rejected) ifTrue: [self error: 'Promise was already resolved'].
-               value := arg.
-               state := #fulfilled.
-               resolvers do: [:r |
-                       self evaluateResolver: r]].!

Item was changed:
  ----- Method: Promise>>then: (in category 'monad') -----
  then: resolvedBlock
+       ^ self then: resolvedBlock ifRejected: [:e | "Pass rejection reason along" e].!
-       ^ self then: resolvedBlock ifRejected: [:ignored | "Do nothing"].!


_,,,^..^,,,_
best, Eliot


Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Kernel-tonyg.1148.mcz

Tobias Pape
In reply to this post by David T. Lewis

> On 02.02.2018, at 04:20, David T. Lewis <[hidden email]> wrote:
>
> Tony has a set of inbox submissions in Kernel, Multilingual, and MultilingualTests
> that appear to be ready to move to trunk.
>
> Should we move these to trunk? If no objections I will move them a few days
> from now if no one else has gotten to it by then.
>
> There will be some new test failures for UTF8EdgeCaseTest, which is a good
> thing since these are new tests that document existing issues.

Yes please

>
> Dave
>
>
> On Thu, Feb 01, 2018 at 10:02:22AM +0000, Tony Garnock-Jones wrote:
>> Hi Eliot,
>>
>> On 02/01/2018 12:34 AM, Eliot Miranda wrote:
>>>    +?? ?? ?? ??(arg isKindOf: Promise)
>>>
>>> I'd /much/ rather see Object>>isPromise and Promise>>isPromise than this.
>>
>> Excellent point! Thanks.
>>
>> There is a Promise>>isPromise, but no matching Object>>isPromise.
>>
>> Kernel-tonyg.1150 (just committed to Inbox) reintroduces it, and
>> switches from using isKindOf: to using isPromise.
>>
>> This change is also in keeping with the spirit of Promises/A+, where
>> anything that is "thenable" is treated as promise-like.
>>
>> Tony
>>
>