Issues with a current promises specification.

250 views
Skip to first unread message

Irakli Gozalishvili

unread,
Nov 26, 2010, 6:28:35 AM11/26/10
to CommonJS, Kris Kowal, Kris Zyp

I have been playing with harmony [Proxies](http://wiki.ecmascript.org/doku.php?id=harmony:proxies) and Promises this days and have discovered few issues which I would like to bring your attention on, since I believe it needs to be addressed by adding more details to current promise spec and reducing functionality defined by specifications.


# Proxy + Promises #

I'm experimenting with an idea of meta programmable promises using [ES Harmony Proxies](http://wiki.ecmascript.org/doku.php?id=harmony:proxies) that is being shipped in Firefox 4. The idea is to allow following:

var { defer, print } = require('meta-promise')
var deferred = defer()
print(deferred.promise.foo.bar.name) // Special print that prints when promise is resolved
print(deferred.promise.baz())        // This does not works yet.
setTimeout(function() { // use require('timer').setTimeout on jetpack deferred.resolve({ foo: { bar: { name: 'Hello meta-promise!' } }, baz: function() { return 'Hello method' } }) }, 100) // you will see 'Hello meta-promise!' in 100ms



Working prototype is can be found here: https://github.com/Gozala/meta-promise
Prototype uses Q implementation of promise/b: https://github.com/kriskowal/q

# Problem #

Promises/A defines several methods  `then, call, get` to be defined on a promise object, which limits Proxy based implementation in a sense that fulfilling values may not have properties with those names.

Promises/B has no such a limitation, but implementation has (emit function no promise object), and it also assumes that promise
is an instance of Promise that makes it impossible to implement promise.baz() Since promise.baz  will have to be a function which can't be an instance of `Promise` (unless Promise === Function). While it's strictly an implementation detail of Q and can be fixed, I do think it's pretty important detail and specification should define it.

Currently specification for Promise/B declares following:

A promise is an opaque object:
  1. How to send messages to a promise object is beyond the scope of this specification.
  2. How to detect whether a value is a promise object is beyond the scope of this specification.
  3. These behaviors are an exercise left to implementers.
  4. Users of promises must not depend on any particular implementation's behavior.
I would like to propose to move forward with something different:

1. Define the way to instantiate promises.
2. Define the way to detect whether a value is a promise or not.
3. Define the way to detect state of promise, whether it is fulfilled / resolved, pending / unresolved, broken / rejected / failed.
4. Define the way messages can be send to a promise object.
5. Define the way to listen to a promise state changes.

To support Proxy based promises this APIs will have to be exposed through a non promise instance itself. In fact I think that's only thing promise spec should define, everything else (that is currently defined by promises a/b) can and should be implemented as a library conforming to promise spec.

As you know I wrote a proposal few days ago https://gist.github.com/711766 which I believe was defining exactly that, but it was not allowing functions to be a promises. I have adjusted it to support this scenario as well.

Please consider issues being described here and try to be constructive. It's not an attempt to ratify some proposal, we just need
a spec compatible with a new features coming to a language.

Regards
--
Irakli Gozalishvili
Web: http://www.jeditoolkit.com/
Address: 29 Rue Saint-Georges, 75009 Paris, France

Kris Zyp

unread,
Nov 26, 2010, 11:08:42 AM11/26/10
to Irakli Gozalishvili, CommonJS
We have long lived with language defined properties to workaround (toString, hasOwnProperty, etc.), and having then() on a proxy proxy-based promise is of negligible consequence. Proxy-based promises are great, but I looked through some of my code that makes extensive use of promises, and use cases for proxied interaction were almost non-existent because code paths tend always end up interacting with primitives that can't be proxied. Promises that resolve to arrays can effectively already be proxied by with array methods (and promised-io and everything builts on uses proxied arrays, AKA lazy arrays, extensively). Object-style interaction is what benefits from proxies and even in this case, performance considerations would often preclude the use of proxies. Ultimately promises need shallow continuations much more than proxies to have better language support.

Defining then() as the basis of promises is elegantly simple, convenient, allows multiple independent implementations, is widely implemented, and is the right solution even if proxies are someday introduced in EcmaScript.

-- 
Thanks,
Kris

Irakli Gozalishvili

unread,
Nov 26, 2010, 12:18:08 PM11/26/10
to Kris Zyp, CommonJS

Don't you you think that it's natural that your code tend to take a different paths if proxy based promises were not possible ?
 
Promises that resolve to arrays can effectively already be proxied by with array methods (and promised-io and everything builts on uses proxied arrays, AKA lazy arrays, extensively). Object-style interaction is what benefits from proxies and even in this case, performance considerations would often preclude the use of proxies.
  

Ultimately promises need shallow continuations much more than proxies to have better language support.


That is entirely different topic and I think ECMAScript mailing list is better place to discuss that.
 
Defining then() as the basis of promises is elegantly simple, convenient, allows multiple independent implementations, is widely implemented,

I'm not arguing that.
 
and is the right solution even if proxies are someday introduced in EcmaScript.


I don't think that there is any solution for all problems. In  jetpack we do have a use cases where proxy based  promises would provide more elegant solution. Also our target engine does have Proxies.

All I'm asking for is to try and rethink a spec that is compatible with Proxy based promises, maybe it's not a right solution in many cases, but in some it is.

-- Thanks, Kris

Kris Kowal

unread,
Nov 26, 2010, 3:28:35 PM11/26/10
to comm...@googlegroups.com
The possibility of using proxies for promises is one of the reasons I
was in favor of making their implementation explicitly undefined for
now. Last time I talked to Mark Miller, he mentioned that using
proxies instead of the promise Q.get, Q.put, &c meta-API was
suboptimal but I don't recall the reasons. I've only recently come to
understand that CapTP would work better if a certain write-barrier
were observable from JavaScript so it could relax the order in which
promises are communicated to remote workers. I am in favor of
experimentation with the promise implementation and I like this
direction.

I've also added an isResolved method to my Q prototype and it seems to
be working well. I'll work on adding an isRejected.

Kris Kowal

Reply all
Reply to author
Forward
0 new messages