TL;DR: I'm willing to entertain a new specification that defines
promises as a duck-type as in Promises/A but also provides a basis for
the Q API laid out in Promises/B. Promises would be defined as an
object that has a function with a particular name that can receive
arbitrary messages of the form promise[DUCK](operator, resolved, …)
and would be required to return rejected promises for unsupported
operators. I've coded this up to verify that the approach would work
and would in fact be a trivial change.
...
Thenables serve as a duck-type: any object with a "then" method is
considered a promise, but it lacks the generality of the "ref_send"
API because it only permits one message type ("then") to be sent
instead of a gamut of message types ("when", "get", "put", "post", and
arbitrary extensions with method-missing fallback).
Tyler Close's implementation of "ref_send" uses function objects as
the duck type. You send messages to a promise simply by calling it:
promise("when", resolved, rejected)
promise("get", resolved, "a")
So, I've revised my implementation of Promises/B in my
"experiment-ducks" branch of the Q package for NPM to use a
"duck-type". Here's the change-set.
https://github.com/kriskowal/q/commit/424e0f8c8d5c8974bcaf71d18bf2400abca33f22
There are no behavioral regressions. The "emit" method serves to
denote the duck-type, but I've changed the name of the method to an
unwieldy string as a place-holder. Since this string is never directly
used, and since it is ideal to avoid collisions, we are free here to
specify an unwieldy name.
This change implies the following specification:
A promise is an object that has a property named $DUCK$ that is a function.
And then the specification would need to define exactly how the Q API
sends messages to the promise object. This is essentially codified by
the implementation and restricted by the Promises/B specification.
For example, this is how the "Q.when" method works:
https://github.com/kriskowal/q/blob/424e0f8c8d5c8974bcaf71d18bf2400abca33f22/lib/q.js#L303-320
As you can see, this guards against erroneous and malicious
implementations of the DUCK method, preserving the guarantees charted
in Promises/B, while also observing the constraint that the promise
object is a duck-type.
...
I created an item that can be commented and voted on in our
bettermeans.com workstream.
https://secure.bettermeans.com/projects/520
Kris Kowal
$DUCK$ was intended as a place-holder for any other, reasonably
unlikely to collide name. It was essentially "emit" in my former
implementation, but that is not sufficient to distinguish it from many
other objects that are legitimate resolution values. So, yeah, when it
comes time to bikeshed, we'll need a list of nominees.
Kris
http://wiki.commonjs.org/wiki/Promises/D
These combine the strength of "thenables" that there can be multiple
interoperable instances of the promise API defined in Promises/B, and
the ability to forward arbitrary messages to promises (not just
"then/when"). This capability is important for using promises as
primitives in distributed computing, which I've managed to get
prototyped in https://github.com/kriskowal/q-comm using a Promises/B
implementation.
Kris Kowal
--
You received this message because you are subscribed to the Google Groups "CommonJS" group.
To post to this group, send email to comm...@googlegroups.com.
To unsubscribe from this group, send email to commonjs+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/commonjs?hl=en.
Sure.
> 2. A promise MUST implement "valueOf" ? Should not spec clarify what does
> return value of that method is ?
The second section describes the proper return-values for "valueOf()"
in each of the promise roles. I'll annotate.
Kris Kowal
On second thought, all objects respond to valueOf() anyway, so it's
non-normative and I've removed this point. The clarifications on what
valueOf() should return remain in the second section.
Kris Kowal
Kris Kowal
Not really. The trick with Q.isRejected(promise) is that it has to
return a literal value in the same turn as the call. Q.when must
guarantee that the callbacks are called in future turns. But, come to
think of it, we could use Q.asap in my prototype, although there are
folks here who would like Q.asap to die a quick death, probably
rightly so.
Kris Kowal
Q.def(object) locks an object to the current worker. This is necessary
to distinguish JSON serializable objects from instances with methods
that close on internal, unserializable state, when you have promises
communicating through message passing.
This is an example of the use of Q.def that allows a server to give a
client access to a local object with a shutdown method:
https://github.com/kriskowal/q-comm/blob/master/examples/messages.2/server.js#L7-11
A client gets a promise for this remote object here:
https://github.com/kriskowal/q-comm/blob/master/examples/messages.2/shutdown.js#L12
And thus can send a "shutdown" message to the remote object. Without
Q.def around the object on the server-side, the client would have
resolve the "remote" promise with the JSON
serialization-deserialization of the remote object, which would have
been simply an empty object {} since closures are not serialized by
JSON.
Kris Kowal