Closed michaelfig closed 4 years ago
For get
indeed it is a realistic worry.
For the others, it is the kind of incompat-in-theory that tc39 has repeatedly gotten away with. If we run into an actual conflict, then we revisit. (See smooshgate)
We could standardise on "eventualGet" "eventualMethod" and "eventualFunction", for more clarity.
eventualGet
is perfect, if we can find terms for the other two that work with it.
eventualGet
works well because it is adjective-verb, where the verb is the delayed operation.
eventualMethod
and eventualFunction
don't work, because it doesn't name the delayed operation.
eventualApply
and eventualSend
?
eventualSend
will need to be explained, but that is the term we generally use to refer to that operation.
I don’t think an “eventual” prefix makes sense, “resolve” is “eventual resolve” foo. Everything on Promise is eventual.
Resolve isn't eventual. It happens immediately.
The get
or apply
isn't happening on the promise, it is happening on what the promise designates. The promise delays the operation but eventually performs it, or arranges for it to eventually happen, on the designated thing.
Even aside from whether the resolve
is immediate or eventual, it is the promise that's resolved, not the thing it designates.
eventualGet
is perfect, if we can find terms for the other two that work with it.eventualGet
works well because it is adjective-verb, where the verb is the delayed operation.
eventualApply
andeventualSend
?
eventualSend
will need to be explained, but that is the term we generally use to refer to that operation.
I can buy that: "send these arguments to that method". I will tackle that also in this PR.
The intent is that users will basically never need these methods, so it makes sense to make them difficult to spell.
[
eventualGet
],eventualApply
andeventualSend
?
How would we spell the sendOnly
variants? And what should the handler traps be called?
How would we spell the sendOnly variants?
eventualGetOnly
(rarely useful. Did we decide to keep or remove this one?)eventualApplyOnly
eventualSendOnly
And what should the handler traps be called?
If we use the term "send" in eventualSend
we should stop using the term "send" in, for example, internal methods like [[GetSend]]
. So we haven't fully settled the names yet.
Suggestions for internal methods and trap names with no conflicting "send"?
Suggestions for internal methods and trap names with no conflicting "send"?
Have all the internal methods and traps named the same:
Promise.eventualGet(p, prop)
, handler.eventualGet
, [[EventualGet]]
Promise.eventualApply(p, args)
, handler.eventualApply
, [[EventualApply]]
Promise.eventualSend(p, prop, args)
, handler.eventualSend
, [[EventualSend]]
and the same with the *Only
suffix.
@erights promise resolution doesn't observably happen immediately; i think the mental model is that everything on promises is eventual, and the prefix "eventual" here is confusing.
@michaelfig I like it!
@ljharb it is not my mental model. Would be good to get some external evidence. Can you find any explanations of what resolve
does, where the explanation says or implies that the promise does not make an immediate transition to the "resolved" (or "settled", "fulfilled", "rejected") state?
Flipping the question around, would "eventual*" not immediately transition a Promise to a resolved fate? If not, then what distinguishes it from being resolved—what is possible on it that wouldn't be possible on a value from Promise.resolve(…)
, or impossible on it that would be possible on the latter?
I'm saying that the immediate transition of the internal state is largely irrelevant (conceptually), since it's impossible to synchronously observe the internal state of the promise.
Since your point is about mental models, we should gather data from people not on this thread.
Btw, we have been explaining this computational model for decades http://www.erights.org/elib/concurrency/refmech.html http://www.erights.org/talks/promises/paper/tgc05.pdf
That explanation has the promise transitions happen immediately, and called "resolve".
The only inter-object interaction in E is via method calls. We have always explained the contrast between
bob.foo(carol)
and
bob <- foo(carol) // JS: bob~.foo(carol)
by describing the first as an immediate call and the latter as an eventual send. http://www.erights.org/elib/concurrency/semi-transparent.html
Choice of words isn't only about what people's mental models are; it is also about suggesting what mental models to form. Explaining promises and eventual method calls in these terms has worked very well. I have never seen confusion of the form "But isn't the resolve transition also eventual?".
Attn @codehag
It's worth noting that, prior to the tildot syntactic sugar, people use the E
shorthand an eventual send thus
E(bob).foo(carol)
The E
stands for eventual.
With the tildot syntactic sugar, we explain that both ?.
and ~.
can be understood as "adjective dot". The natural adjective to attach to the tilda is "eventual"
Flipping the question around, would "eventual*" not immediately transition a Promise to a resolved fate? If not, then what distinguishes it from being resolved—what is possible on it that wouldn't be possible on a value from
Promise.resolve(…)
, or impossible on it that would be possible on the latter?
The eventual*
static methods invoke a delegated Promise's unfulfilled handler in a future turn, but before the promise has fulfilled. If a delegated promise is fulfilled to a presence, then the eventual*
static methods invoke the presence's handler in a future turn. If the target is not a delegated promise (whether ordinary Promise, thenable, or other entity), then the eventual*
methods wait for the target's fulfilment, then execute the default, and guarantee that at least one turn passes before the fulfilment is accessed.
Flipping the question around, would "eventual*" not immediately transition a Promise to a resolved fate? If not, then what distinguishes it from being resolved—what is possible on it that wouldn't be possible on a value from
Promise.resolve(…)
, or impossible on it that would be possible on the latter?The
eventual*
static methods invoke a delegated Promise's unfulfilled handler in a future turn, but before the promise has fulfilled. If a delegated promise is fulfilled to a presence, then theeventual*
static methods invoke the presence's handler in a future turn. If the target is not a delegated promise (whether ordinary Promise, thenable, or other entity), then theeventual*
methods wait for the target's fulfilment, then execute the default, and guarantee that at least one turn passes before the fulfilment is accessed.
I'm sorry, but that doesn't seem like a satisfactory answer, perhaps because the terms are not clear. A non-delegated Promise, upon becoming resolved (such as by Promise.resolve(value)
), will subsequently ignore all external resolution attempts and instead wait for internal settlement via the value and then invoke its appropriate handlers in a later turn (which, if it has already been settled, will be the very next turn).
I understand that there are additional handlers/traps for delegated Promises, but that's not what I'm asking about—I'm asking about what it is possible to observe or do with the value returned from e.g. Promise.eventualGet(obj, prop)
(literally so, with no other captured state) that would be different than the value returned from Promise.resolve(obj).then(obj => obj[prop])
. I'm interested in the traps beyond that point, but am still trying to establish a baseline comprehension.
I understand that there are additional handlers/traps for delegated Promises, but that's not what I'm asking about—I'm asking about what it is possible to observe or do with the value returned from e.g.
Promise.eventualGet(obj, prop)
(literally so, with no other captured state) that would be different than the value returned fromPromise.resolve(obj).then(obj => obj[prop])
. I'm interested in the traps beyond that point, but am still trying to establish a baseline comprehension.
No difference in observance for things that are not delegated Promises. The methods are only useful for things that might be a delegated Promise. If you don't use delegated Promises at all, then the methods don't buy you anything, and even if you do use delegated Promises, we are just proposing the static methods for things the tildot transform (or something like the E proxy maker) would reduce to, not something you'd actually write by hand.
This is merged already. I was pinged late on Friday Evening so I will give my comments now. I had to ramp up on the proposal, so I might have missed some stuff here.
The eventual*
prefix doesn't tell me what it does, and my expectation would be different based on the name. If I understood the changes correctly,eventualGet
first resolves a promise with a value and then calls a method on it. I would not expect that. I would have expected it to only be short hand for extracting a property. for example
given
var callback = function (resolve, reject, resolveWithPresence) { ... resolve({foo: ..} }) // unclear if this is how it would work...
var x = Promise.delegate(callback, onUnfullfilledCallback);
Promise.eventualGet(x, prop) // unclear what prop is from the readme, is it a string?
I would expect, something like this but with remote powers:
var x = new Promise ((resolve, reject) => {... return { foo: ...}); // promise is resolved outside of our direct control of the promise
x.then(t => t.foo);
but what it does (if I got it right) is
Promise.resolve({ foo: ... }).then(x => x.foo);
I am surprised that the resolution of the promise is under our control, and not something coming from the outside. In order to express the second behavior better, maybe something like resolveGet
, resolveApply
?
Closes #11