Skip to content
This repository has been archived by the owner on Jan 22, 2025. It is now read-only.

Postpone coercion and unwrapping to time-of-use #369

Closed
kriskowal opened this issue Aug 21, 2013 · 2 comments
Closed

Postpone coercion and unwrapping to time-of-use #369

kriskowal opened this issue Aug 21, 2013 · 2 comments
Milestone

Comments

@kriskowal
Copy link
Owner

Discussion about promises and monads over on ESDiscuss has trended toward a good idea to postpone attempts to unwrap or coerce promises until they are used. At present, we unwrap them, recursively, at the earliest possible time, e.g., deferred.resolve(promiseOrValueOrThenable). This is a proposal to postpone coercion until deferredPromise.then() is called. This might be generalizable to “whenever a message is passed to the promise”. This will facilitate lazy promises postponing work deeper into Q’s internals, and will also postpone thenable assimilation until the wrapped promise is “thened”, which more closely matches expectations.

cc @erights, @domenic

@domenic
Copy link
Collaborator

domenic commented Aug 21, 2013

See also promises-aplus/promises-spec#128, wherein a few implementers have shared their work on this. It appears to be largely painless.

@kriskowal
Copy link
Owner Author

@domenic, I slept on it. I’m pretty sure it’s just a matter of moving some stuff in become into defer’s promiseDispatch, and throwing a flag in there so that we only coerce once.

kriskowal added a commit that referenced this issue Aug 27, 2013
Regarding #369

Among other things, if Q wraps a thenable, this postpones coercion until
the consumer attempts to use the promise.  Before, `Q(thenable)` would
call `thenable.then` as soon as possible, but now the user must go all
the way to `Q(thenable).then()` in order for `thenable.then()` to be
invoked.  This is less surprising in principle.

This is achived by adding an "accepted" state to deferred promises,
between "pending" and "resolved".  This state is reflected by
`deferred.promise.inspect()`.

This change breaks many specs, which need to be reviewed and probably
fixed.
kriskowal added a commit that referenced this issue Oct 30, 2013
Implement the `Promise` constructor.  The promise constructor serves
both as a deferred promise constructor that accepts a function, and a
new kind of promise constructor that accepts a backing handler object.
The backing handler object must implement `dispatch(resolve, op,
operands)` and `inspect()`.  The new promise constructor replaces the
`Q.promise` function, which is deprecated.  The new promise constructor
replaces `makePromise`, which has been removed entirely.  As such,
Q-Connection will have to be rearchitected to provide a custom promise
handler for remote objects instead of using `makePromise`. Fixes #346.

Postpone calling `then` on a thenable until a message is dispatched to
the coerced promise.  Fixes #372. Fixes #369.

When coercing a thenable, memoize the resulting promise to avoid
re-starting a lazy promise.

Add support for vicious cycle detection.  Fixes #223.

This change request also reviews the Q API, deprecating many interfaces
that remain from legacy designs.  Fixes #215.

Factor most Node.js tools into `q/node` module.  Mirror deprecated
interfaces in Q.

Support for `close` and `closed` has been removed from `Queue`, which
has additional ramifications for Q-Connection.  I intend to use Q-IO
streams in Q-Connection instead of raw queues.

Most of the Q specifications continue to work after these changes, but
with many deprecation warnings.  The specs have been revised to appease
the deprecation warnings.

:warning: However, the specifications for "progress" have all been
disabled pending a closer investigation to decide whether to fix Q or
fix the specs.

The promise protocol no longer supports "set" and "delete" operations.
Function application is a special case of "post", and for support of
"fbind", it is now possible to pass a "thisp" as a final argument.  The
"when" message is now called simply "then".

Support for pre-ECMAScript 5 has been abandoned outright, pending
review.

Removed:

-   Q.set, promise.set
-   Q.delete, promise.delete
-   Q.nearer
-   Q.master

The following methods of `Q` are deprecated in favor of their
equivalents on the `promise` prototype:

-   `progress`, `thenResolve`, `thenReject`, `isPending`, `isFulfilled`,
    `isRejected`, `dispatch`, `get`, `post`, `invoke`, `keys`

Other deprecations:

-   Q.resolve in favor of Q
-   Q.fulfill in favor of Q
-   Q.isPromiseAlike in favor of Q.isThenable
-   Q.when in favor of Q().then
-   Q.fail and promise.fail in favor of promise.catch
-   Q.fin and promise.fin in favor of promise.finally
-   Q.mapply and promise.mapply in favor of promise.post
-   Q.send and promise.send in favor of promise.invoke
-   Q.mcall and promise.mcall in favor of promise.invoke
-   Q.promise in favor of new Q.Promise with a resolver function
-   Q.makePromise in favor of new Q.Promise with a handler object
-   promise.fbind in favor of Q.fbind
-   deferred.makeNodeResolver() in favor of
    require("q/node").makeNodeResolver(deferred.resolve)
-   promise.passByCopy() in favor of Q.passByCopy(promise),
    provisionally

Node.js wrappers that have been moved into their own module have a
deprecated interface in Q proper:

-   `nodeify`, `denodify`, `nfbind`, `nbind`, `npost`, `ninvoke`

But the following experimental aliases are deprecated and do not exist
in `q/node`:

-   `nsend` for `ninvoke`
-   `nmcall` for `ninvoke`
-   `nmapply` for `npost`
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants