[hidden email] wrote: > On Tue, Jan 26, 2016 at 5:56 PM, Herby Vojčík <[hidden email] > <mailto:[hidden email]>> wrote: > > > > Dňa 26. januára 2016 16:54:51 CET používateľ "[hidden email] > <mailto:[hidden email]>" <[hidden email] > <mailto:[hidden email]>> napísal: > >I faced internal resistance at first when meeting promises but as > it is > >what makes the "modern" web what it (e.g. angular style coding), we > > I don't know what you mean by angular style coding. I do not use > angular but use promises (and ES6 ones, not q, bluebird or any other > lib). > > > JS with promises style. > > > >need to > >embrace that. > > > >Otherwise, it is nightmarish to use all of the APIs etc. > > > >Parens are no problem for me FWIW. > > In JS, I find it ok. In Amber, parentheses would make me mad (hence, > chaining helper of this or that sort). But as I said, I find 8 > members of [all:]then:[on:do:][catch:] family with array in then: > feasible (or 6 members of > [all:]then:[on:do:|catch:]). > > > yes, this looks a nice avenue to go down. > > > >How would you see reject used? > > I don't understand. You mean Promise.reject convenience API or > reject in executor? > > > Promise.reject I don't know if you use it often. It is a convenience method, it can be always be done via executor, so presently I do not see the need to wrap it, as I wrote. This should be enough: Promise asyncFromBlock: [ :model | model signal: 'foo' ] But it's IMO. > >Phil Herby -- You received this message because you are subscribed to the Google Groups "amber-lang" group. To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]. For more options, visit https://groups.google.com/d/optout. |
In reply to this post by Herby Vojčík
Second version, after Philippe Back's suggestions:
Object >> asPromise "returns a Promise resolved to self" <return JS_Promise.resolve(self)> JSObjectProxy >> asPromise <return JS_Promise.resolve(self["@jsObject"])> Promise class >> forBlock: aBlock "Inspired by GNU Smalltalk API. Returns a Promise fulfilled or rejected by `aBlock value`. Only usable for synchronous operations in aBlock." ^ aBlock valueAsPromise BlockClosure >> valueAsPromise <return JS_Promise.resolve().then(function () {return self._value()})> Promise class >> asyncForBlock: aBlock "aBlock is called with PromiseModel object. `aPromiseModel value: x` resolves the promise. `aPromiseModel signal: y` rejects the promise. Returns a Promise that eventually succeeds or fails, asynchronously." ^ aBlock newPromise BlockClosure >> newPromise "self is called with PromiseModel object. `aPromiseModel value: x` resolves the promise. `aPromiseModel signal: y` rejects the promise. Returns a Promise that eventually succeeds or fails, asynchronously." <return new JS_Promise(function (resolve, reject) { return self._value_($globals.PromiseModel._newResolve_reject_( resolve, reject )); })> PromiseModel class >> newResolve: aBlock reject: anotherBlock "Creates a PromiseModel instance that calls aBlock when anInstance value: is sent and calls anotherBlock when anInstance signal: is sent." PromiseModel >> value: anObject "Resolves underlying promise." PromiseModel >> signal: anObject "Rejects underlying promise." Collection >> allAsPromise "Returns a collection that succeeds when all promises in self asArray succeed. It is resolved with array of their results." ^ self asArray allAsPromise Array >> allAsPromise <return JS_Promise.all(self._collect_(function (each) { return each._asPromise(); }))> Promise class >> all: aCollection "Returns a collection that succeeds when all promises in aCollection succeed. It is resolved with array of their results." ^ aCollection allAsPromise Collection >> anyAsPromise "Returns a collection that succeeds when any of the promises in self asArray succeed. It is resolved with result of the first one that resolves." ^ self asArray anyAsPromise Array >> anyAsPromise <return JS_Promise.any(self._collect_(function (each) { return each._asPromise(); }))> Promise class >> any: aCollection "Returns a collection that succeeds when any of the promises in aCollection succeed. It is resolved with result of the first one that resolves." ^ aCollection anyAsPromise Promise >> all:then:on:do: Promise >> all:then:catch: Promise >> all:then: Promise >> then:on:do: Promise >> then:catch: Promise >> then: "all: nadicBlock then: aBlockOrCollectionOfBlocks on: aClass do: catchBlock catch: catchAllBlock" <return self // if all: present .then(function(args) { return nadicBlock._valueWithPossibleArguments_(args); }) // if then: arg is aBlock .then(function (result) { return aBlock._value_(result); }) // if then: arg is collection of blocks, // thenArg do: [ :each | "add .then call as above" ] // if on: aClass do: catchBlock present .catch(function (ex) { if ($recv(ex)._isKindOf_(aClass) return catchBlock._value_(ex); else throw ex; }) // if catch: catchAllBlock is present .catch(function (ex) { return catchAllBlock._value_(ex); }) > As you can see, Promise.reject API is not wrapped, but I don't it's needed than often and can always be done with `[ :m | m signal: 'foo' ] newPromise`. For example: (fetch value: url) then: { [ :data | JSON parse: data]. [ :parsed | parsed at: #id ifAbsent: [ Error signal: "Missing name."]. parsed ]. ... } catch: [ :e | self handleError: e ofUrl: url ] and creating promise of your own: [ :model | anObject apiWithCallback: [ :err :result | err ifNotNil: [ model signal: err ] ifNil: [ console log: result. model value: result payload ] ] ] newPromise Opinions? Thanks, Herby -- You received this message because you are subscribed to the Google Groups "amber-lang" group. To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]. For more options, visit https://groups.google.com/d/optout. |
Herby Vojčík wrote: > Second version, after Philippe Back's suggestions: > > Object >> asPromise > "returns a Promise resolved to self" > <return JS_Promise.resolve(self)> > > JSObjectProxy >> asPromise > <return JS_Promise.resolve(self["@jsObject"])> > > Promise class >> forBlock: aBlock > "Inspired by GNU Smalltalk API. > Returns a Promise fulfilled or rejected by `aBlock value`. > Only usable for synchronous operations in aBlock." > ^ aBlock valueAsPromise > > BlockClosure >> valueAsPromise > <return JS_Promise.resolve().then(function () {return self._value()})> > > Promise class >> asyncForBlock: aBlock > "aBlock is called with PromiseModel object. > `aPromiseModel value: x` resolves the promise. > `aPromiseModel signal: y` rejects the promise. > Returns a Promise that eventually > succeeds or fails, asynchronously." > ^ aBlock newPromise > > BlockClosure >> newPromise > "self is called with PromiseModel object. > `aPromiseModel value: x` resolves the promise. > `aPromiseModel signal: y` rejects the promise. > Returns a Promise that eventually > succeeds or fails, asynchronously." > <return new JS_Promise(function (resolve, reject) { > return self._value_($globals.PromiseModel._newResolve_reject_( > resolve, reject > )); > })> > > PromiseModel class >> newResolve: aBlock reject: anotherBlock > "Creates a PromiseModel instance > that calls aBlock when anInstance value: is sent > and calls anotherBlock when anInstance signal: is sent." > > PromiseModel >> value: anObject > "Resolves underlying promise." > > PromiseModel >> signal: anObject > "Rejects underlying promise." > > Collection >> allAsPromise > "Returns a collection that succeeds > when all promises in self asArray succeed. > It is resolved with array of their results." > ^ self asArray allAsPromise > > Array >> allAsPromise > <return JS_Promise.all(self._collect_(function (each) { > return each._asPromise(); > }))> > > Promise class >> all: aCollection > "Returns a collection that succeeds > when all promises in aCollection succeed. > It is resolved with array of their results." > ^ aCollection allAsPromise > > Collection >> anyAsPromise > "Returns a collection that succeeds "Returns a promise that ... > when any of the promises in self asArray succeed. > It is resolved with result of the first one that resolves." > ^ self asArray anyAsPromise > > Array >> anyAsPromise > <return JS_Promise.any(self._collect_(function (each) { > return each._asPromise(); > }))> > > Promise class >> any: aCollection > "Returns a collection that succeeds > when any of the promises in aCollection succeed. > It is resolved with result of the first one that resolves." > ^ aCollection anyAsPromise > > Promise >> all:then:on:do: > Promise >> all:then:catch: > Promise >> all:then: > Promise >> then:on:do: > Promise >> then:catch: > Promise >> then: > "all: nadicBlock > then: aBlockOrCollectionOfBlocks > on: aClass do: catchBlock > catch: catchAllBlock" > <return self > // if all: present > .then(function(args) { > return nadicBlock._valueWithPossibleArguments_(args); > }) > // if then: arg is aBlock > .then(function (result) { > return aBlock._value_(result); > }) > // if then: arg is collection of blocks, > // thenArg do: [ :each | "add .then call as above" ] > // if on: aClass do: catchBlock present > .catch(function (ex) { > if ($recv(ex)._isKindOf_(aClass) > return catchBlock._value_(ex); > else throw ex; > }) > // if catch: catchAllBlock is present > .catch(function (ex) { > return catchAllBlock._value_(ex); > }) > > > > As you can see, Promise.reject API is not wrapped, but I don't it's > needed than often and can always be done with `[ :m | m signal: 'foo' ] > newPromise`. > > For example: > > (fetch value: url) > then: { > [ :data | JSON parse: data]. > [ :parsed | > parsed at: #id ifAbsent: [ Error signal: "Missing name."]. > parsed ]. > ... > } > catch: [ :e | self handleError: e ofUrl: url ] > > and creating promise of your own: > > [ :model | > anObject apiWithCallback: [ :err :result | err > ifNotNil: [ model signal: err ] > ifNil: [ console log: result. model value: result payload ] ] > ] newPromise > > Opinions? > > Thanks, Herby > -- You received this message because you are subscribed to the Google Groups "amber-lang" group. To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]. For more options, visit https://groups.google.com/d/optout. |
I see one more problem with this. As the ecosystem is now, there is not
just ES2015 Promise (native or polyfilled), that is, the global Promise, but many frameworks use different implementations (Parse has its own Parse.Promise, Angular has $q, there are Q and Bluebird implementations which are also dependencies of some libraries). So, Amber must actually be able to provide functionality for all major implementations. The way how to achieve it is, IMO, having AbstractPromise base class with basic functionality, using only minimal subset (.then(null, fn) instead of .catch(fn) etc.) and letting the rest on subclasses, while providing subclass Promise that wraps global Promise expecting it to be ES2015 one, but adding other AbstractPromise-derived wrappers for other types of promises, installable as libraries. Herby Vojčík wrote: > > > Herby Vojčík wrote: >> Second version, after Philippe Back's suggestions: >> >> Object >> asPromise >> "returns a Promise resolved to self" >> <return JS_Promise.resolve(self)> >> >> JSObjectProxy >> asPromise >> <return JS_Promise.resolve(self["@jsObject"])> >> >> Promise class >> forBlock: aBlock >> "Inspired by GNU Smalltalk API. >> Returns a Promise fulfilled or rejected by `aBlock value`. >> Only usable for synchronous operations in aBlock." >> ^ aBlock valueAsPromise >> >> BlockClosure >> valueAsPromise >> <return JS_Promise.resolve().then(function () {return self._value()})> >> >> Promise class >> asyncForBlock: aBlock >> "aBlock is called with PromiseModel object. >> `aPromiseModel value: x` resolves the promise. >> `aPromiseModel signal: y` rejects the promise. >> Returns a Promise that eventually >> succeeds or fails, asynchronously." >> ^ aBlock newPromise >> >> BlockClosure >> newPromise >> "self is called with PromiseModel object. >> `aPromiseModel value: x` resolves the promise. >> `aPromiseModel signal: y` rejects the promise. >> Returns a Promise that eventually >> succeeds or fails, asynchronously." >> <return new JS_Promise(function (resolve, reject) { >> return self._value_($globals.PromiseModel._newResolve_reject_( >> resolve, reject >> )); >> })> >> >> PromiseModel class >> newResolve: aBlock reject: anotherBlock >> "Creates a PromiseModel instance >> that calls aBlock when anInstance value: is sent >> and calls anotherBlock when anInstance signal: is sent." >> >> PromiseModel >> value: anObject >> "Resolves underlying promise." >> >> PromiseModel >> signal: anObject >> "Rejects underlying promise." >> >> Collection >> allAsPromise >> "Returns a collection that succeeds > "Returns a promise that ... >> when all promises in self asArray succeed. >> It is resolved with array of their results." >> ^ self asArray allAsPromise >> >> Array >> allAsPromise >> <return JS_Promise.all(self._collect_(function (each) { >> return each._asPromise(); >> }))> >> >> Promise class >> all: aCollection >> "Returns a collection that succeeds > "Returns a promise that ... >> when all promises in aCollection succeed. >> It is resolved with array of their results." >> ^ aCollection allAsPromise >> >> Collection >> anyAsPromise >> "Returns a collection that succeeds > "Returns a promise that ... >> when any of the promises in self asArray succeed. >> It is resolved with result of the first one that resolves." >> ^ self asArray anyAsPromise >> >> Array >> anyAsPromise >> <return JS_Promise.any(self._collect_(function (each) { >> return each._asPromise(); >> }))> >> >> Promise class >> any: aCollection >> "Returns a collection that succeeds > "Returns a promise that ... >> when any of the promises in aCollection succeed. >> It is resolved with result of the first one that resolves." >> ^ aCollection anyAsPromise >> >> Promise >> all:then:on:do: >> Promise >> all:then:catch: >> Promise >> all:then: >> Promise >> then:on:do: >> Promise >> then:catch: >> Promise >> then: >> "all: nadicBlock >> then: aBlockOrCollectionOfBlocks >> on: aClass do: catchBlock >> catch: catchAllBlock" >> <return self >> // if all: present >> .then(function(args) { >> return nadicBlock._valueWithPossibleArguments_(args); >> }) >> // if then: arg is aBlock >> .then(function (result) { >> return aBlock._value_(result); >> }) >> // if then: arg is collection of blocks, >> // thenArg do: [ :each | "add .then call as above" ] >> // if on: aClass do: catchBlock present >> .catch(function (ex) { >> if ($recv(ex)._isKindOf_(aClass) >> return catchBlock._value_(ex); >> else throw ex; >> }) >> // if catch: catchAllBlock is present >> .catch(function (ex) { >> return catchAllBlock._value_(ex); >> }) >> > >> >> As you can see, Promise.reject API is not wrapped, but I don't it's >> needed than often and can always be done with `[ :m | m signal: 'foo' ] >> newPromise`. >> >> For example: >> >> (fetch value: url) >> then: { >> [ :data | JSON parse: data]. >> [ :parsed | >> parsed at: #id ifAbsent: [ Error signal: "Missing name."]. >> parsed ]. >> ... >> } >> catch: [ :e | self handleError: e ofUrl: url ] >> >> and creating promise of your own: >> >> [ :model | >> anObject apiWithCallback: [ :err :result | err >> ifNotNil: [ model signal: err ] >> ifNil: [ console log: result. model value: result payload ] ] >> ] newPromise >> >> Opinions? >> >> Thanks, Herby >> > -- You received this message because you are subscribed to the Google Groups "amber-lang" group. To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]. For more options, visit https://groups.google.com/d/optout. |
Isn't is why Promise/A+ exists? On Jan 28, 2016 4:57 PM, "Herby Vojčík" <[hidden email]> wrote:
-- I see one more problem with this. As the ecosystem is now, there is not just ES2015 Promise (native or polyfilled), that is, the global Promise, but many frameworks use different implementations (Parse has its own Parse.Promise, Angular has $q, there are Q and Bluebird implementations which are also dependencies of some libraries). You received this message because you are subscribed to the Google Groups "amber-lang" group. To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]. For more options, visit https://groups.google.com/d/optout. |
One thing is API. There are insustry standards like Promise/A+ but they are minimal. Things like Promise.all or Promise.resolve differ beyween implementations. Some have finally, some have not.
(luckily, Parse was death-sentenced today by fb, so need not take it into account) Second thing is, how Amber wraps native classes (combined with the fact that when you combine libs, you end up with different promise implementations side by side (and working together if only thing you take into account is .then)). Class wrapping in Amber is 1-to-1 correspondence. What means, if you have more implementations side by side, you need to wrap every one of them to have the transparency of just using then: family API for all of them. Hence, the idea of abstract base class with API and subclasses actually wrapping JS classes. Dňa 28. januára 2016 19:15:06 CET používateľ "[hidden email]" <[hidden email]> napísal: >Isn't is why Promise/A+ exists? >On Jan 28, 2016 4:57 PM, "Herby Vojčík" <[hidden email]> wrote: > >> I see one more problem with this. As the ecosystem is now, there is >not >> just ES2015 Promise (native or polyfilled), that is, the global >Promise, >> but many frameworks use different implementations (Parse has its own >> Parse.Promise, Angular has $q, there are Q and Bluebird >implementations >> which are also dependencies of some libraries). >> >> So, Amber must actually be able to provide functionality for all >major >> implementations. >> >> The way how to achieve it is, IMO, having AbstractPromise base class >with >> basic functionality, using only minimal subset (.then(null, fn) >instead of >> .catch(fn) etc.) and letting the rest on subclasses, while providing >> subclass Promise that wraps global Promise expecting it to be ES2015 >one, >> but adding other AbstractPromise-derived wrappers for other types of >> promises, installable as libraries. >> >> Herby Vojčík wrote: >> >>> >>> >>> Herby Vojčík wrote: >>> >>>> Second version, after Philippe Back's suggestions: >>>> >>>> Object >> asPromise >>>> "returns a Promise resolved to self" >>>> <return JS_Promise.resolve(self)> >>>> >>>> JSObjectProxy >> asPromise >>>> <return JS_Promise.resolve(self["@jsObject"])> >>>> >>>> Promise class >> forBlock: aBlock >>>> "Inspired by GNU Smalltalk API. >>>> Returns a Promise fulfilled or rejected by `aBlock value`. >>>> Only usable for synchronous operations in aBlock." >>>> ^ aBlock valueAsPromise >>>> >>>> BlockClosure >> valueAsPromise >>>> <return JS_Promise.resolve().then(function () {return >self._value()})> >>>> >>>> Promise class >> asyncForBlock: aBlock >>>> "aBlock is called with PromiseModel object. >>>> `aPromiseModel value: x` resolves the promise. >>>> `aPromiseModel signal: y` rejects the promise. >>>> Returns a Promise that eventually >>>> succeeds or fails, asynchronously." >>>> ^ aBlock newPromise >>>> >>>> BlockClosure >> newPromise >>>> "self is called with PromiseModel object. >>>> `aPromiseModel value: x` resolves the promise. >>>> `aPromiseModel signal: y` rejects the promise. >>>> Returns a Promise that eventually >>>> succeeds or fails, asynchronously." >>>> <return new JS_Promise(function (resolve, reject) { >>>> return self._value_($globals.PromiseModel._newResolve_reject_( >>>> resolve, reject >>>> )); >>>> })> >>>> >>>> PromiseModel class >> newResolve: aBlock reject: anotherBlock >>>> "Creates a PromiseModel instance >>>> that calls aBlock when anInstance value: is sent >>>> and calls anotherBlock when anInstance signal: is sent." >>>> >>>> PromiseModel >> value: anObject >>>> "Resolves underlying promise." >>>> >>>> PromiseModel >> signal: anObject >>>> "Rejects underlying promise." >>>> >>>> Collection >> allAsPromise >>>> "Returns a collection that succeeds >>>> >>> "Returns a promise that ... >>> >>>> when all promises in self asArray succeed. >>>> It is resolved with array of their results." >>>> ^ self asArray allAsPromise >>>> >>>> Array >> allAsPromise >>>> <return JS_Promise.all(self._collect_(function (each) { >>>> return each._asPromise(); >>>> }))> >>>> >>>> Promise class >> all: aCollection >>>> "Returns a collection that succeeds >>>> >>> "Returns a promise that ... >>> >>>> when all promises in aCollection succeed. >>>> It is resolved with array of their results." >>>> ^ aCollection allAsPromise >>>> >>>> Collection >> anyAsPromise >>>> "Returns a collection that succeeds >>>> >>> "Returns a promise that ... >>> >>>> when any of the promises in self asArray succeed. >>>> It is resolved with result of the first one that resolves." >>>> ^ self asArray anyAsPromise >>>> >>>> Array >> anyAsPromise >>>> <return JS_Promise.any(self._collect_(function (each) { >>>> return each._asPromise(); >>>> }))> >>>> >>>> Promise class >> any: aCollection >>>> "Returns a collection that succeeds >>>> >>> "Returns a promise that ... >>> >>>> when any of the promises in aCollection succeed. >>>> It is resolved with result of the first one that resolves." >>>> ^ aCollection anyAsPromise >>>> >>>> Promise >> all:then:on:do: >>>> Promise >> all:then:catch: >>>> Promise >> all:then: >>>> Promise >> then:on:do: >>>> Promise >> then:catch: >>>> Promise >> then: >>>> "all: nadicBlock >>>> then: aBlockOrCollectionOfBlocks >>>> on: aClass do: catchBlock >>>> catch: catchAllBlock" >>>> <return self >>>> // if all: present >>>> .then(function(args) { >>>> return nadicBlock._valueWithPossibleArguments_(args); >>>> }) >>>> // if then: arg is aBlock >>>> .then(function (result) { >>>> return aBlock._value_(result); >>>> }) >>>> // if then: arg is collection of blocks, >>>> // thenArg do: [ :each | "add .then call as above" ] >>>> // if on: aClass do: catchBlock present >>>> .catch(function (ex) { >>>> if ($recv(ex)._isKindOf_(aClass) >>>> return catchBlock._value_(ex); >>>> else throw ex; >>>> }) >>>> // if catch: catchAllBlock is present >>>> .catch(function (ex) { >>>> return catchAllBlock._value_(ex); >>>> }) >>>> > >>>> >>>> As you can see, Promise.reject API is not wrapped, but I don't it's >>>> needed than often and can always be done with `[ :m | m signal: >'foo' ] >>>> newPromise`. >>>> >>>> For example: >>>> >>>> (fetch value: url) >>>> then: { >>>> [ :data | JSON parse: data]. >>>> [ :parsed | >>>> parsed at: #id ifAbsent: [ Error signal: "Missing name."]. >>>> parsed ]. >>>> ... >>>> } >>>> catch: [ :e | self handleError: e ofUrl: url ] >>>> >>>> and creating promise of your own: >>>> >>>> [ :model | >>>> anObject apiWithCallback: [ :err :result | err >>>> ifNotNil: [ model signal: err ] >>>> ifNil: [ console log: result. model value: result payload ] ] >>>> ] newPromise >>>> >>>> Opinions? >>>> >>>> Thanks, Herby >>>> >>>> >>> >> -- >> You received this message because you are subscribed to the Google >Groups >> "amber-lang" group. >> To unsubscribe from this group and stop receiving emails from it, >send an >> email to [hidden email]. >> For more options, visit https://groups.google.com/d/optout. >> -- Odoslané z môjho Android zariadenia pomocou K-9 Mail. -- You received this message because you are subscribed to the Google Groups "amber-lang" group. To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]. For more options, visit https://groups.google.com/d/optout. |
In reply to this post by Herby Vojčík
There is one more problem as I see it: there surely will be promises
created as inline objects, as here: https://github.com/requirejs/alameda-prim/commit/9ad546fff02b765ebe6943929218d07c1f2c655d#diff-aeb8d45ae32f6d853d4ac616eb5875b9R138. This means, we must actually implement all:then:on:do:catch: family of messages in JSObjectProxy as well, and catch all thenables dynamically. What also means, there is enough to wrap the official global Promise, let the others be caught by JSObjectProxy, and people can wrap other implementations if they see it fit / it helps them with performance issues / it allows them create promises of a specific library. So I would say, create a base class called Thenable with *then:* family. Then, subclass Promise wrapping global ES2015 Promise and also *then:* family in JSObjectProxy which can test dynamically if typeof self.then === "function" && (self.catch == null || typeof self.catch === "function") and if yes, delegate to Thenable to do the work on self. Herby Herby Vojčík wrote: > I see one more problem with this. As the ecosystem is now, there is not > just ES2015 Promise (native or polyfilled), that is, the global Promise, > but many frameworks use different implementations (Parse has its own > Parse.Promise, Angular has $q, there are Q and Bluebird implementations > which are also dependencies of some libraries). > > So, Amber must actually be able to provide functionality for all major > implementations. > > The way how to achieve it is, IMO, having AbstractPromise base class > with basic functionality, using only minimal subset (.then(null, fn) > instead of .catch(fn) etc.) and letting the rest on subclasses, while > providing subclass Promise that wraps global Promise expecting it to be > ES2015 one, but adding other AbstractPromise-derived wrappers for other > types of promises, installable as libraries. > > Herby Vojčík wrote: >> >> >> Herby Vojčík wrote: >>> Second version, after Philippe Back's suggestions: >>> >>> Object >> asPromise >>> "returns a Promise resolved to self" >>> <return JS_Promise.resolve(self)> >>> >>> JSObjectProxy >> asPromise >>> <return JS_Promise.resolve(self["@jsObject"])> >>> >>> Promise class >> forBlock: aBlock >>> "Inspired by GNU Smalltalk API. >>> Returns a Promise fulfilled or rejected by `aBlock value`. >>> Only usable for synchronous operations in aBlock." >>> ^ aBlock valueAsPromise >>> >>> BlockClosure >> valueAsPromise >>> <return JS_Promise.resolve().then(function () {return self._value()})> >>> >>> Promise class >> asyncForBlock: aBlock >>> "aBlock is called with PromiseModel object. >>> `aPromiseModel value: x` resolves the promise. >>> `aPromiseModel signal: y` rejects the promise. >>> Returns a Promise that eventually >>> succeeds or fails, asynchronously." >>> ^ aBlock newPromise >>> >>> BlockClosure >> newPromise >>> "self is called with PromiseModel object. >>> `aPromiseModel value: x` resolves the promise. >>> `aPromiseModel signal: y` rejects the promise. >>> Returns a Promise that eventually >>> succeeds or fails, asynchronously." >>> <return new JS_Promise(function (resolve, reject) { >>> return self._value_($globals.PromiseModel._newResolve_reject_( >>> resolve, reject >>> )); >>> })> >>> >>> PromiseModel class >> newResolve: aBlock reject: anotherBlock >>> "Creates a PromiseModel instance >>> that calls aBlock when anInstance value: is sent >>> and calls anotherBlock when anInstance signal: is sent." >>> >>> PromiseModel >> value: anObject >>> "Resolves underlying promise." >>> >>> PromiseModel >> signal: anObject >>> "Rejects underlying promise." >>> >>> Collection >> allAsPromise >>> "Returns a collection that succeeds >> "Returns a promise that ... >>> when all promises in self asArray succeed. >>> It is resolved with array of their results." >>> ^ self asArray allAsPromise >>> >>> Array >> allAsPromise >>> <return JS_Promise.all(self._collect_(function (each) { >>> return each._asPromise(); >>> }))> >>> >>> Promise class >> all: aCollection >>> "Returns a collection that succeeds >> "Returns a promise that ... >>> when all promises in aCollection succeed. >>> It is resolved with array of their results." >>> ^ aCollection allAsPromise >>> >>> Collection >> anyAsPromise >>> "Returns a collection that succeeds >> "Returns a promise that ... >>> when any of the promises in self asArray succeed. >>> It is resolved with result of the first one that resolves." >>> ^ self asArray anyAsPromise >>> >>> Array >> anyAsPromise >>> <return JS_Promise.any(self._collect_(function (each) { >>> return each._asPromise(); >>> }))> >>> >>> Promise class >> any: aCollection >>> "Returns a collection that succeeds >> "Returns a promise that ... >>> when any of the promises in aCollection succeed. >>> It is resolved with result of the first one that resolves." >>> ^ aCollection anyAsPromise >>> >>> Promise >> all:then:on:do: >>> Promise >> all:then:catch: >>> Promise >> all:then: >>> Promise >> then:on:do: >>> Promise >> then:catch: >>> Promise >> then: >>> "all: nadicBlock >>> then: aBlockOrCollectionOfBlocks >>> on: aClass do: catchBlock >>> catch: catchAllBlock" >>> <return self >>> // if all: present >>> .then(function(args) { >>> return nadicBlock._valueWithPossibleArguments_(args); >>> }) >>> // if then: arg is aBlock >>> .then(function (result) { >>> return aBlock._value_(result); >>> }) >>> // if then: arg is collection of blocks, >>> // thenArg do: [ :each | "add .then call as above" ] >>> // if on: aClass do: catchBlock present >>> .catch(function (ex) { >>> if ($recv(ex)._isKindOf_(aClass) >>> return catchBlock._value_(ex); >>> else throw ex; >>> }) >>> // if catch: catchAllBlock is present >>> .catch(function (ex) { >>> return catchAllBlock._value_(ex); >>> }) >>> > >>> >>> As you can see, Promise.reject API is not wrapped, but I don't it's >>> needed than often and can always be done with `[ :m | m signal: 'foo' ] >>> newPromise`. >>> >>> For example: >>> >>> (fetch value: url) >>> then: { >>> [ :data | JSON parse: data]. >>> [ :parsed | >>> parsed at: #id ifAbsent: [ Error signal: "Missing name."]. >>> parsed ]. >>> ... >>> } >>> catch: [ :e | self handleError: e ofUrl: url ] >>> >>> and creating promise of your own: >>> >>> [ :model | >>> anObject apiWithCallback: [ :err :result | err >>> ifNotNil: [ model signal: err ] >>> ifNil: [ console log: result. model value: result payload ] ] >>> ] newPromise >>> >>> Opinions? >>> >>> Thanks, Herby >>> >> > -- You received this message because you are subscribed to the Google Groups "amber-lang" group. To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]. For more options, visit https://groups.google.com/d/optout. |
Ok I see. We need a couple of real examples (like in the Async Javascript book) I think, so that we can explore a couple cases properly. Phil On Jan 29, 2016 10:24 PM, "Herby Vojčík" <[hidden email]> wrote:
-- There is one more problem as I see it: there surely will be promises created as inline objects, as here: https://github.com/requirejs/alameda-prim/commit/9ad546fff02b765ebe6943929218d07c1f2c655d#diff-aeb8d45ae32f6d853d4ac616eb5875b9R138. This means, we must actually implement all:then:on:do:catch: family of messages in JSObjectProxy as well, and catch all thenables dynamically. You received this message because you are subscribed to the Google Groups "amber-lang" group. To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]. For more options, visit https://groups.google.com/d/optout. |
[hidden email] wrote: > Ok I see. > > We need a couple of real examples (like in the Async Javascript book) I > think, so that we can explore a couple cases properly. > > Phil I in fact think that implementing just the bare minimum I envisioned is doable fast (in fact only thing needed is to do the JSObjectProxy part, but I would include the Thenable class there as well, so the delegation is put up properly). Creating the promises is then still hard because it must use JS API which is less Smalltalk-like ('reject value: x' is not as English-sentence-like like 'model signal: x'), but the main part will be there. I am just a bit tired to do it just now, but I can probably do it somewhere in the weekend, and even release it. I want to add more promises to startup process, mainly, making amber.initialize({...}) return a promise, but for that would need more work with polyfilling for non-Promise environments. > > On Jan 29, 2016 10:24 PM, "Herby Vojčík" <[hidden email] > <mailto:[hidden email]>> wrote: > > There is one more problem as I see it: there surely will be promises > created as inline objects, as here: > https://github.com/requirejs/alameda-prim/commit/9ad546fff02b765ebe6943929218d07c1f2c655d#diff-aeb8d45ae32f6d853d4ac616eb5875b9R138. > This means, we must actually implement all:then:on:do:catch: family > of messages in JSObjectProxy as well, and catch all thenables > dynamically. > > What also means, there is enough to wrap the official global > Promise, let the others be caught by JSObjectProxy, and people can > wrap other implementations if they see it fit / it helps them with > performance issues / it allows them create promises of a specific > library. > > So I would say, create a base class called Thenable with *then:* > family. Then, subclass Promise wrapping global ES2015 Promise and > also *then:* family in JSObjectProxy which can test dynamically if > typeof self.then === "function" && (self.catch == null || typeof > self.catch === "function") and if yes, delegate to Thenable to do > the work on self. > > Herby > > Herby Vojčík wrote: > > I see one more problem with this. As the ecosystem is now, there > is not > just ES2015 Promise (native or polyfilled), that is, the global > Promise, > but many frameworks use different implementations (Parse has its own > Parse.Promise, Angular has $q, there are Q and Bluebird > implementations > which are also dependencies of some libraries). > > So, Amber must actually be able to provide functionality for all > major > implementations. > > The way how to achieve it is, IMO, having AbstractPromise base class > with basic functionality, using only minimal subset (.then(null, fn) > instead of .catch(fn) etc.) and letting the rest on subclasses, > while > providing subclass Promise that wraps global Promise expecting > it to be > ES2015 one, but adding other AbstractPromise-derived wrappers > for other > types of promises, installable as libraries. > > Herby Vojčík wrote: > > > > Herby Vojčík wrote: > > Second version, after Philippe Back's suggestions: > > Object >> asPromise > "returns a Promise resolved to self" > <return JS_Promise.resolve(self)> > > JSObjectProxy >> asPromise > <return JS_Promise.resolve(self["@jsObject"])> > > Promise class >> forBlock: aBlock > "Inspired by GNU Smalltalk API. > Returns a Promise fulfilled or rejected by `aBlock value`. > Only usable for synchronous operations in aBlock." > ^ aBlock valueAsPromise > > BlockClosure >> valueAsPromise > <return JS_Promise.resolve().then(function () {return > self._value()})> > > Promise class >> asyncForBlock: aBlock > "aBlock is called with PromiseModel object. > `aPromiseModel value: x` resolves the promise. > `aPromiseModel signal: y` rejects the promise. > Returns a Promise that eventually > succeeds or fails, asynchronously." > ^ aBlock newPromise > > BlockClosure >> newPromise > "self is called with PromiseModel object. > `aPromiseModel value: x` resolves the promise. > `aPromiseModel signal: y` rejects the promise. > Returns a Promise that eventually > succeeds or fails, asynchronously." > <return new JS_Promise(function (resolve, reject) { > return > self._value_($globals.PromiseModel._newResolve_reject_( > resolve, reject > )); > })> > > PromiseModel class >> newResolve: aBlock reject: > anotherBlock > "Creates a PromiseModel instance > that calls aBlock when anInstance value: is sent > and calls anotherBlock when anInstance signal: is sent." > > PromiseModel >> value: anObject > "Resolves underlying promise." > > PromiseModel >> signal: anObject > "Rejects underlying promise." > > Collection >> allAsPromise > "Returns a collection that succeeds > > "Returns a promise that ... > > when all promises in self asArray succeed. > It is resolved with array of their results." > ^ self asArray allAsPromise > > Array >> allAsPromise > <return JS_Promise.all(self._collect_(function (each) { > return each._asPromise(); > }))> > > Promise class >> all: aCollection > "Returns a collection that succeeds > > "Returns a promise that ... > > when all promises in aCollection succeed. > It is resolved with array of their results." > ^ aCollection allAsPromise > > Collection >> anyAsPromise > "Returns a collection that succeeds > > "Returns a promise that ... > > when any of the promises in self asArray succeed. > It is resolved with result of the first one that resolves." > ^ self asArray anyAsPromise > > Array >> anyAsPromise > <return JS_Promise.any(self._collect_(function (each) { > return each._asPromise(); > }))> > > Promise class >> any: aCollection > "Returns a collection that succeeds > > "Returns a promise that ... > > when any of the promises in aCollection succeed. > It is resolved with result of the first one that resolves." > ^ aCollection anyAsPromise > > Promise >> all:then:on:do: > Promise >> all:then:catch: > Promise >> all:then: > Promise >> then:on:do: > Promise >> then:catch: > Promise >> then: > "all: nadicBlock > then: aBlockOrCollectionOfBlocks > on: aClass do: catchBlock > catch: catchAllBlock" > <return self > // if all: present > .then(function(args) { > return nadicBlock._valueWithPossibleArguments_(args); > }) > // if then: arg is aBlock > .then(function (result) { > return aBlock._value_(result); > }) > // if then: arg is collection of blocks, > // thenArg do: [ :each | "add .then call as above" ] > // if on: aClass do: catchBlock present > .catch(function (ex) { > if ($recv(ex)._isKindOf_(aClass) > return catchBlock._value_(ex); > else throw ex; > }) > // if catch: catchAllBlock is present > .catch(function (ex) { > return catchAllBlock._value_(ex); > }) > > > > As you can see, Promise.reject API is not wrapped, but I > don't it's > needed than often and can always be done with `[ :m | m > signal: 'foo' ] > newPromise`. > > For example: > > (fetch value: url) > then: { > [ :data | JSON parse: data]. > [ :parsed | > parsed at: #id ifAbsent: [ Error signal: "Missing name."]. > parsed ]. > ... > } > catch: [ :e | self handleError: e ofUrl: url ] > > and creating promise of your own: > > [ :model | > anObject apiWithCallback: [ :err :result | err > ifNotNil: [ model signal: err ] > ifNil: [ console log: result. model value: result > payload ] ] > ] newPromise > > Opinions? > > Thanks, Herby > > > > > -- > You received this message because you are subscribed to the Google > Groups "amber-lang" group. > To unsubscribe from this group and stop receiving emails from it, > send an email to [hidden email] > <mailto:amber-lang%[hidden email]>. > For more options, visit https://groups.google.com/d/optout. > > -- > You received this message because you are subscribed to the Google > Groups "amber-lang" group. > To unsubscribe from this group and stop receiving emails from it, send > an email to [hidden email] > <mailto:[hidden email]>. > For more options, visit https://groups.google.com/d/optout. -- You received this message because you are subscribed to the Google Groups "amber-lang" group. To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]. For more options, visit https://groups.google.com/d/optout. |
Sweet. Take care, I'll follow along. Phil On Jan 29, 2016 11:31 PM, "Herby Vojčík" <[hidden email]> wrote:
--
You received this message because you are subscribed to the Google Groups "amber-lang" group. To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]. For more options, visit https://groups.google.com/d/optout. |
I am thinking about removing all: and giving then: blocks ability to
take array elements. A result would always go to first argument, but if the block would have more arguments in its definition and the result is an array, first n-1 elements of an array would be passed to additional arguments. Is it too crazy (if one wants to eschew that, one can always one one-arg block and do things on its own)? Herby [hidden email] wrote: > Sweet. Take care, I'll follow along. > Maybe we can do a new podcast episode about current Amber and promises. > > Phil > > On Jan 29, 2016 11:31 PM, "Herby Vojčík" <[hidden email] > <mailto:[hidden email]>> wrote: > > > > [hidden email] <mailto:[hidden email]> wrote: > > Ok I see. > > We need a couple of real examples (like in the Async Javascript > book) I > think, so that we can explore a couple cases properly. > > Phil > > > I in fact think that implementing just the bare minimum I envisioned > is doable fast (in fact only thing needed is to do the JSObjectProxy > part, but I would include the Thenable class there as well, so the > delegation is put up properly). Creating the promises is then still > hard because it must use JS API which is less Smalltalk-like > ('reject value: x' is not as English-sentence-like like 'model > signal: x'), but the main part will be there. > > I am just a bit tired to do it just now, but I can probably do it > somewhere in the weekend, and even release it. I want to add more > promises to startup process, mainly, making amber.initialize({...}) > return a promise, but for that would need more work with polyfilling > for non-Promise environments. > > > On Jan 29, 2016 10:24 PM, "Herby Vojčík" <[hidden email] > <mailto:[hidden email]> > <mailto:[hidden email] <mailto:[hidden email]>>> wrote: > > There is one more problem as I see it: there surely will be > promises > created as inline objects, as here: > https://github.com/requirejs/alameda-prim/commit/9ad546fff02b765ebe6943929218d07c1f2c655d#diff-aeb8d45ae32f6d853d4ac616eb5875b9R138. > This means, we must actually implement > all:then:on:do:catch: family > of messages in JSObjectProxy as well, and catch all thenables > dynamically. > > What also means, there is enough to wrap the official global > Promise, let the others be caught by JSObjectProxy, and > people can > wrap other implementations if they see it fit / it helps > them with > performance issues / it allows them create promises of a > specific > library. > > So I would say, create a base class called Thenable with > *then:* > family. Then, subclass Promise wrapping global ES2015 > Promise and > also *then:* family in JSObjectProxy which can test > dynamically if > typeof self.then === "function" && (self.catch == null || > typeof > self.catch === "function") and if yes, delegate to Thenable > to do > the work on self. > > Herby > > Herby Vojčík wrote: > > I see one more problem with this. As the ecosystem is > now, there > is not > just ES2015 Promise (native or polyfilled), that is, > the global > Promise, > but many frameworks use different implementations > (Parse has its own > Parse.Promise, Angular has $q, there are Q and Bluebird > implementations > which are also dependencies of some libraries). > > So, Amber must actually be able to provide > functionality for all > major > implementations. > > The way how to achieve it is, IMO, having > AbstractPromise base class > with basic functionality, using only minimal subset > (.then(null, fn) > instead of .catch(fn) etc.) and letting the rest on > subclasses, > while > providing subclass Promise that wraps global Promise > expecting > it to be > ES2015 one, but adding other AbstractPromise-derived > wrappers > for other > types of promises, installable as libraries. > > Herby Vojčík wrote: > > > > Herby Vojčík wrote: > > Second version, after Philippe Back's suggestions: > > Object >> asPromise > "returns a Promise resolved to self" > <return JS_Promise.resolve(self)> > > JSObjectProxy >> asPromise > <return JS_Promise.resolve(self["@jsObject"])> > > Promise class >> forBlock: aBlock > "Inspired by GNU Smalltalk API. > Returns a Promise fulfilled or rejected by > `aBlock value`. > Only usable for synchronous operations in aBlock." > ^ aBlock valueAsPromise > > BlockClosure >> valueAsPromise > <return JS_Promise.resolve().then(function () {return > self._value()})> > > Promise class >> asyncForBlock: aBlock > "aBlock is called with PromiseModel object. > `aPromiseModel value: x` resolves the promise. > `aPromiseModel signal: y` rejects the promise. > Returns a Promise that eventually > succeeds or fails, asynchronously." > ^ aBlock newPromise > > BlockClosure >> newPromise > "self is called with PromiseModel object. > `aPromiseModel value: x` resolves the promise. > `aPromiseModel signal: y` rejects the promise. > Returns a Promise that eventually > succeeds or fails, asynchronously." > <return new JS_Promise(function (resolve, reject) { > return > > self._value_($globals.PromiseModel._newResolve_reject_( > resolve, reject > )); > })> > > PromiseModel class >> newResolve: aBlock reject: > anotherBlock > "Creates a PromiseModel instance > that calls aBlock when anInstance value: is sent > and calls anotherBlock when anInstance signal: > is sent." > > PromiseModel >> value: anObject > "Resolves underlying promise." > > PromiseModel >> signal: anObject > "Rejects underlying promise." > > Collection >> allAsPromise > "Returns a collection that succeeds > > "Returns a promise that ... > > when all promises in self asArray succeed. > It is resolved with array of their results." > ^ self asArray allAsPromise > > Array >> allAsPromise > <return JS_Promise.all(self._collect_(function (each) { > return each._asPromise(); > }))> > > Promise class >> all: aCollection > "Returns a collection that succeeds > > "Returns a promise that ... > > when all promises in aCollection succeed. > It is resolved with array of their results." > ^ aCollection allAsPromise > > Collection >> anyAsPromise > "Returns a collection that succeeds > > "Returns a promise that ... > > when any of the promises in self asArray succeed. > It is resolved with result of the first one > that resolves." > ^ self asArray anyAsPromise > > Array >> anyAsPromise > <return JS_Promise.any(self._collect_(function (each) { > return each._asPromise(); > }))> > > Promise class >> any: aCollection > "Returns a collection that succeeds > > "Returns a promise that ... > > when any of the promises in aCollection succeed. > It is resolved with result of the first one > that resolves." > ^ aCollection anyAsPromise > > Promise >> all:then:on:do: > Promise >> all:then:catch: > Promise >> all:then: > Promise >> then:on:do: > Promise >> then:catch: > Promise >> then: > "all: nadicBlock > then: aBlockOrCollectionOfBlocks > on: aClass do: catchBlock > catch: catchAllBlock" > <return self > // if all: present > .then(function(args) { > return > nadicBlock._valueWithPossibleArguments_(args); > }) > // if then: arg is aBlock > .then(function (result) { > return aBlock._value_(result); > }) > // if then: arg is collection of blocks, > // thenArg do: [ :each | "add .then call as > above" ] > // if on: aClass do: catchBlock present > .catch(function (ex) { > if ($recv(ex)._isKindOf_(aClass) > return catchBlock._value_(ex); > else throw ex; > }) > // if catch: catchAllBlock is present > .catch(function (ex) { > return catchAllBlock._value_(ex); > }) > > > > As you can see, Promise.reject API is not > wrapped, but I > don't it's > needed than often and can always be done with > `[ :m | m > signal: 'foo' ] > newPromise`. > > For example: > > (fetch value: url) > then: { > [ :data | JSON parse: data]. > [ :parsed | > parsed at: #id ifAbsent: [ Error signal: > "Missing name."]. > parsed ]. > ... > } > catch: [ :e | self handleError: e ofUrl: url ] > > and creating promise of your own: > > [ :model | > anObject apiWithCallback: [ :err :result | err > ifNotNil: [ model signal: err ] > ifNil: [ console log: result. model value: result > payload ] ] > ] newPromise > > Opinions? > > Thanks, Herby > > > > > -- > You received this message because you are subscribed to the > Groups "amber-lang" group. > To unsubscribe from this group and stop receiving emails > from it, > send an email to [hidden email] > <mailto:amber-lang%[hidden email]> > <mailto:amber-lang%[hidden email] > <mailto:amber-lang%[hidden email]>>. > For more options, visit https://groups.google.com/d/optout. > > -- > You received this message because you are subscribed to the Google > Groups "amber-lang" group. > To unsubscribe from this group and stop receiving emails from > it, send > an email to [hidden email] > <mailto:amber-lang%[hidden email]> > <mailto:[hidden email] > <mailto:amber-lang%[hidden email]>>. > For more options, visit https://groups.google.com/d/optout. > > > -- > You received this message because you are subscribed to the Google > Groups "amber-lang" group. > To unsubscribe from this group and stop receiving emails from it, > send an email to [hidden email] > <mailto:amber-lang%[hidden email]>. > For more options, visit https://groups.google.com/d/optout. > > -- > You received this message because you are subscribed to the Google > Groups "amber-lang" group. > To unsubscribe from this group and stop receiving emails from it, send > an email to [hidden email] > <mailto:[hidden email]>. > For more options, visit https://groups.google.com/d/optout. -- You received this message because you are subscribed to the Google Groups "amber-lang" group. To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]. For more options, visit https://groups.google.com/d/optout. |
Looks okay. On Mon, Feb 1, 2016 at 11:21 PM, Herby Vojčík <[hidden email]> wrote: I am thinking about removing all: and giving then: blocks ability to take array elements. A result would always go to first argument, but if the block would have more arguments in its definition and the result is an array, first n-1 elements of an array would be passed to additional arguments. Is it too crazy (if one wants to eschew that, one can always one one-arg block and do things on its own)? You received this message because you are subscribed to the Google Groups "amber-lang" group. To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]. For more options, visit https://groups.google.com/d/optout. |
A little problem during implementation.
When I do 'PP=Promise' in JS console (so as to have access to JS Promise) and do (JSObjectProxy on: PP) resolve then: [ :x | Error signal: 'intentional' ] catch: [ :err | Transcript show: err; cr ] then error is shown in the Transcript, but before that it is caught by debugger. Some change allowing "unsafe" run of ST code from JS must be done to boot.js for this to work as expected. :-( [hidden email] wrote: > Looks okay. > > On Mon, Feb 1, 2016 at 11:21 PM, Herby Vojčík <[hidden email] > <mailto:[hidden email]>> wrote: > > I am thinking about removing all: and giving then: blocks ability to > take array elements. A result would always go to first argument, but > if the block would have more arguments in its definition and the > result is an array, first n-1 elements of an array would be passed > to additional arguments. Is it too crazy (if one wants to eschew > that, one can always one one-arg block and do things on its own)? > > Herby > > [hidden email] <mailto:[hidden email]> wrote: > > Sweet. Take care, I'll follow along. > Maybe we can do a new podcast episode about current Amber and > promises. > > Phil > > On Jan 29, 2016 11:31 PM, "Herby Vojčík" <[hidden email] > <mailto:[hidden email]> > <mailto:[hidden email] <mailto:[hidden email]>>> wrote: > > > > [hidden email] <mailto:[hidden email]> > <mailto:[hidden email] <mailto:[hidden email]>> wrote: > > Ok I see. > > We need a couple of real examples (like in the Async > Javascript > book) I > think, so that we can explore a couple cases properly. > > Phil > > > I in fact think that implementing just the bare minimum I > envisioned > is doable fast (in fact only thing needed is to do the > JSObjectProxy > part, but I would include the Thenable class there as well, > so the > delegation is put up properly). Creating the promises is > then still > hard because it must use JS API which is less Smalltalk-like > ('reject value: x' is not as English-sentence-like like 'model > signal: x'), but the main part will be there. > > I am just a bit tired to do it just now, but I can probably > do it > somewhere in the weekend, and even release it. I want to > add more > promises to startup process, mainly, making > amber.initialize({...}) > return a promise, but for that would need more work with > polyfilling > for non-Promise environments. > > > On Jan 29, 2016 10:24 PM, "Herby Vojčík" > <[hidden email] <mailto:[hidden email]> > <mailto:[hidden email] <mailto:[hidden email]>> > <mailto:[hidden email] <mailto:[hidden email]> > <mailto:[hidden email] <mailto:[hidden email]>>>> wrote: > > There is one more problem as I see it: there > surely will be > promises > created as inline objects, as here: > https://github.com/requirejs/alameda-prim/commit/9ad546fff02b765ebe6943929218d07c1f2c655d#diff-aeb8d45ae32f6d853d4ac616eb5875b9R138. > This means, we must actually implement > all:then:on:do:catch: family > of messages in JSObjectProxy as well, and catch > all thenables > dynamically. > > What also means, there is enough to wrap the > official global > Promise, let the others be caught by > JSObjectProxy, and > people can > wrap other implementations if they see it fit / it > helps > them with > performance issues / it allows them create > promises of a > specific > library. > > So I would say, create a base class called > Thenable with > *then:* > family. Then, subclass Promise wrapping global ES2015 > Promise and > also *then:* family in JSObjectProxy which can test > dynamically if > typeof self.then === "function" && (self.catch == > null || > typeof > self.catch === "function") and if yes, delegate to > Thenable > to do > the work on self. > > Herby > > Herby Vojčík wrote: > > I see one more problem with this. As the > ecosystem is > now, there > is not > just ES2015 Promise (native or polyfilled), > that is, > the global > Promise, > but many frameworks use different implementations > (Parse has its own > Parse.Promise, Angular has $q, there are Q and > Bluebird > implementations > which are also dependencies of some libraries). > > So, Amber must actually be able to provide > functionality for all > major > implementations. > > The way how to achieve it is, IMO, having > AbstractPromise base class > with basic functionality, using only minimal > subset > (.then(null, fn) > instead of .catch(fn) etc.) and letting the > rest on > subclasses, > while > providing subclass Promise that wraps global > Promise > expecting > it to be > ES2015 one, but adding other > AbstractPromise-derived > wrappers > for other > types of promises, installable as libraries. > > Herby Vojčík wrote: > > > > Herby Vojčík wrote: > > Second version, after Philippe Back's > suggestions: > > Object >> asPromise > "returns a Promise resolved to self" > <return JS_Promise.resolve(self)> > > JSObjectProxy >> asPromise > <return JS_Promise.resolve(self["@jsObject"])> > > Promise class >> forBlock: aBlock > "Inspired by GNU Smalltalk API. > Returns a Promise fulfilled or rejected by > `aBlock value`. > Only usable for synchronous operations > in aBlock." > ^ aBlock valueAsPromise > > BlockClosure >> valueAsPromise > <return JS_Promise.resolve().then(function () {return > self._value()})> > > Promise class >> asyncForBlock: aBlock > "aBlock is called with PromiseModel object. > `aPromiseModel value: x` resolves the > promise. > `aPromiseModel signal: y` rejects the > promise. > Returns a Promise that eventually > succeeds or fails, asynchronously." > ^ aBlock newPromise > > BlockClosure >> newPromise > "self is called with PromiseModel object. > `aPromiseModel value: x` resolves the > promise. > `aPromiseModel signal: y` rejects the > promise. > Returns a Promise that eventually > succeeds or fails, asynchronously." > <return new JS_Promise(function (resolve, reject) { > return > > self._value_($globals.PromiseModel._newResolve_reject_( > resolve, reject > )); > })> > > PromiseModel class >> newResolve: > aBlock reject: > anotherBlock > "Creates a PromiseModel instance > that calls aBlock when anInstance > value: is sent > and calls anotherBlock when anInstance > signal: > is sent." > > PromiseModel >> value: anObject > "Resolves underlying promise." > > PromiseModel >> signal: anObject > "Rejects underlying promise." > > Collection >> allAsPromise > "Returns a collection that succeeds > > "Returns a promise that ... > > when all promises in self asArray succeed. > It is resolved with array of their > results." > ^ self asArray allAsPromise > > Array >> allAsPromise > <return JS_Promise.all(self._collect_(function (each) { > return each._asPromise(); > }))> > > Promise class >> all: aCollection > "Returns a collection that succeeds > > "Returns a promise that ... > > when all promises in aCollection succeed. > It is resolved with array of their > results." > ^ aCollection allAsPromise > > Collection >> anyAsPromise > "Returns a collection that succeeds > > "Returns a promise that ... > > when any of the promises in self > asArray succeed. > It is resolved with result of the > first one > that resolves." > ^ self asArray anyAsPromise > > Array >> anyAsPromise > <return JS_Promise.any(self._collect_(function (each) { > return each._asPromise(); > }))> > > Promise class >> any: aCollection > "Returns a collection that succeeds > > "Returns a promise that ... > > when any of the promises in > aCollection succeed. > It is resolved with result of the > first one > that resolves." > ^ aCollection anyAsPromise > > Promise >> all:then:on:do: > Promise >> all:then:catch: > Promise >> all:then: > Promise >> then:on:do: > Promise >> then:catch: > Promise >> then: > "all: nadicBlock > then: aBlockOrCollectionOfBlocks > on: aClass do: catchBlock > catch: catchAllBlock" > <return self > // if all: present > .then(function(args) { > return > nadicBlock._valueWithPossibleArguments_(args); > }) > // if then: arg is aBlock > .then(function (result) { > return aBlock._value_(result); > }) > // if then: arg is collection of blocks, > // thenArg do: [ :each | "add .then > call as > above" ] > // if on: aClass do: catchBlock present > .catch(function (ex) { > if ($recv(ex)._isKindOf_(aClass) > return catchBlock._value_(ex); > else throw ex; > }) > // if catch: catchAllBlock is present > .catch(function (ex) { > return catchAllBlock._value_(ex); > }) > > > > As you can see, Promise.reject API is not > wrapped, but I > don't it's > needed than often and can always be > done with > `[ :m | m > signal: 'foo' ] > newPromise`. > > For example: > > (fetch value: url) > then: { > [ :data | JSON parse: data]. > [ :parsed | > parsed at: #id ifAbsent: [ Error signal: > "Missing name."]. > parsed ]. > ... > } > catch: [ :e | self handleError: e > ofUrl: url ] > > and creating promise of your own: > > [ :model | > anObject apiWithCallback: [ :err > :result | err > ifNotNil: [ model signal: err ] > ifNil: [ console log: result. model > value: result > payload ] ] > ] newPromise > > Opinions? > > Thanks, Herby > > > > > -- > You received this message because you are > subscribed to the > Groups "amber-lang" group. > To unsubscribe from this group and stop receiving > emails > from it, > send an email to > [hidden email] > <mailto:amber-lang%[hidden email]> > <mailto:amber-lang%[hidden email] > <mailto:amber-lang%[hidden email]>> > <mailto:amber-lang%[hidden email] > <mailto:amber-lang%[hidden email]> > <mailto:amber-lang%[hidden email] > <mailto:amber-lang%[hidden email]>>>. > For more options, visit > https://groups.google.com/d/optout. > > -- > You received this message because you are subscribed to > the Google > Groups "amber-lang" group. > To unsubscribe from this group and stop receiving > emails from > it, send > an email to [hidden email] > <mailto:amber-lang%[hidden email]> > <mailto:amber-lang%[hidden email] > <mailto:amber-lang%[hidden email]>> > <mailto:[hidden email] > <mailto:amber-lang%[hidden email]> > <mailto:amber-lang%[hidden email] > <mailto:amber-lang%[hidden email]>>>. > For more options, visit https://groups.google.com/d/optout. > > > -- > You received this message because you are subscribed to the > Groups "amber-lang" group. > To unsubscribe from this group and stop receiving emails > from it, > send an email to [hidden email] > <mailto:amber-lang%[hidden email]> > <mailto:amber-lang%[hidden email] > <mailto:amber-lang%[hidden email]>>. > For more options, visit https://groups.google.com/d/optout. > > -- > You received this message because you are subscribed to the Google > Groups "amber-lang" group. > To unsubscribe from this group and stop receiving emails from > it, send > an email to [hidden email] > <mailto:amber-lang%[hidden email]> > <mailto:[hidden email] > <mailto:amber-lang%[hidden email]>>. > For more options, visit https://groups.google.com/d/optout. > > > -- > You received this message because you are subscribed to the Google > Groups "amber-lang" group. > To unsubscribe from this group and stop receiving emails from it, > send an email to [hidden email] > <mailto:amber-lang%[hidden email]>. > For more options, visit https://groups.google.com/d/optout. > > > -- > You received this message because you are subscribed to the Google > Groups "amber-lang" group. > To unsubscribe from this group and stop receiving emails from it, send > an email to [hidden email] > <mailto:[hidden email]>. > For more options, visit https://groups.google.com/d/optout. -- You received this message because you are subscribed to the Google Groups "amber-lang" group. To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]. For more options, visit https://groups.google.com/d/optout. |
Free forum by Nabble | Edit this page |