-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Why is a new promise API needed at all? Why REST? #5
Comments
We want infix bang to be usable to defer operations in code with regular, not-explicitly-handled Promises (in which case Promise.resolve(p) is an identity function), as well as ordinary objects on which you want to make deferred operations. Just as
Handled Promises are not implementable by Proxy, because the Proxy isn't invoked when an object is wrapped with
I'm not the best person to answer this, so maybe @erights or @FUDCo will chime in. Thanks for your comments, |
Oh, and they desugar to Promise API calls because the implementation needs to look up the handler (if any) for the call, and that is a power that cannot be wielded without access to a global object. |
I'm actually not sure how we got to |
I was pretty confused by the table of default behaviors. Ignoring the first two rows, the methods correspond to operations that have existing names in ES ( That they’re the defaults, meant to be implementable with other behaviors, probably goes a good way towards explaining the choice. Nonetheless, it doesn’t seem intuitive to me. In particular — returning to those first two rows — I could not understand why Should an argument-before-the-arguments be there, I’d have expected it to be the receiver, as it is everywhere else ( It’s a very intriguing proposal but I don’t think I really grok it and I think these object-internal-method-but-not-quite operations could use some more explanation. |
@michaelfig thanks for the explanation 😃 I would imagine |
I've been rolling this around in my head for an hour or so and so far I'm unable to figure out how the whole promise api idea is better than just a regular fluent API. // does the proxy magic defined in the readme
target!foo(1, 2, 3).then(console.log) vs // target could even be a proxy similar to the one in the
// readme, calling or returning `queueMessage` on accesses
// and deletions and such.
target.foo(1, 2, 3).then(console.log) |
You have the misfortune of having walked in on a bunch of people who've been using this abstraction for a long time in other contexts and so already know they want it very much in JavaScript.
Since we all have so much shared context, it's easy for us to run on ahead of the crowd and wind up just talking amongst ourselves.
Part of our mission here has got be to do a much better job of explaining these things so we aren't just talking within the comparatively small community of people already steeped in this stuff.
The idea behind promises derives from the idea behind objects.
What is an object? It's something you can send a message to -- and typically get a value back.
What's that value you get back? It's an object. Which is something you can send messages to.
So if you already know the thing you'll get back is something you can send messages to, we can arrange for you to be able to just start sending messages to it right away, even before you have it, since actually getting the value itself might take a long time, especially if the messages have to travel over the network.
You can pipeline this any number of levels deep. The only time you have stall the pipeline is when you actually need to look at the bits, which if you are clever can be surprisingly infrequently.
Calling `console.log` for illustrative purposes is a little misleading because it means you're stalling the pipeline to look at the bits just to demonstrate that it worked, which is not what this is for.
In some use cases, pipelining promises can give you two or three orders of magnitude throughput improvement for distributed computation by avoiding the round trip latencies.
JS promises as currently realized only deliver a fraction of the benefits of a full-blown promise system because they are limited to computation that takes place inside a single JS virtual machine.
The new API provides the hooks to finish the job.
The `!` syntax is desirable because we want to use `!` almost as ubiquitously as we use `.`. You wouldn't dream of using regular JS promises so heavily because it's way too cumbersome.
In other words, it's not so you can write
```targetP!foo(1, 2, 3).then(console.log)```
it's so you can write
```x = targetP!foo(1, 2, 3);
y = x!bar("hello")!baz(4, 5, {thing: 47})!quxx(2);
z = y!somethingelse()!anotherThing()!andAnother();
w = z!transmogrify().then(console.log);```
And maybe foo, bar, baz, quxx, somethingElse, anotherThing, andAnother, and transmogrify all go out in the same network packet.
… On Jul 12, 2019, at 10:06 PM, Gus Caplan ***@***.***> wrote:
I've been rolling this around in my head for an hour or so and so far I'm unable to figure out how the whole promise api idea is better than just a regular fluent API.
// does the proxy magic defined in the readme
targetP!foo(1, 2, 3).then(console.log)
vs
// targetP could even be a proxy similar to the one in the
// readme, calling or returning `queueMessage` on accesses
// and deletions and such.
targetP.foo(1, 2, 3).then(console.log)
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub <#5>, or mute the thread <https://github.com/notifications/unsubscribe-auth/AB5D4WHSF7CUUVJKWKROM63P7FPG7ANCNFSM4ICUHEWA>.
|
I just really don't understand why the chaining needs to involve promises. What constraint or use case is imposing that promises form a MOP here? x = target.foo(1, 2, 3);
y = x.bar("hello").baz(4, 5, {thing: 47}).quxx(2);
z = y.somethingelse().anotherThing().andAnother(); w = z.transmogrify().then(console.log); these can all chain together to not send anything until |
Reasoning about interleaving and reentrancy. When object Alice says
When Alice says
See the Part III of Robust Composition, especially Chapter 14 "Two Ways to Postpone Plans". |
Yes, the names However, I am not stuck on these names. This is indeed something to bikeshed about. |
Deferred evaluation of messages is usually what I’d call “part of a function body”, and then I’d invoke it (for sync) or pass it into .then (for async). Is this proposal effectively sugar for building up a function body, one statement at a time? |
@erights to clarify, you want to call bob but you don't trust bob? with this proposal, you still have to trust that const handler = {
get(t, key) {
if (key === 'then') return doFullTransaction();
const x = () => {};
x.key = key;
return new Proxy(x, handler);
},
apply(t, thisArg, args) {
return queuePartOfTransaction(t.key, args);
},
};
const bob = new Proxy({}, handler);
bob
.foo(1, 2, 3) // queuePartOfTransaction('foo', [1, 2, 3])
.bar() // queuePartOfTransaction('bar', [])
.then(cb) // doFullTransaction, cb handles effects of foo and bar |
For the local case, that works fine, but would sacrifice promise pipelining for the remote case. This could only work once the promise |
@devsnek good catch! Filed https://github.com/Agoric/eventual-send/issues/19 Consider this proposal under the assumption that there will be a protective turn boundary before the handler is invoked. Thanks!! |
I think with my example above, |
x = targetP!foo(1, 2, 3);
y = x!bar("hello")!baz(4, 5, {thing: 47})!quxx(2);
z = y!somethingelse()!anotherThing()!andAnother();
w = z!transmogrify().then(console.log);` could also be written as x = (async () => (await targetP).foo(1,2,3))()
y = (async () => (await (await (await x).bar("hello")).baz(4, 5, {thing: 47})).quxx(2))()
z = (async () => (await (await (await y).somethingelse()).anotherThing()).andAnother())()
w = (async () => console.log(await (await z).transmogrify()))() Right? And that could maybe sugared by combining with tc39/proposal-do-expressions#4 : x = do async (await targetP).foo(1,2,3)
y = do async (await (await (await x).bar("hello")).baz(4, 5, {thing: 47})).quxx(2)
z = do async (await (await (await y).somethingelse()).anotherThing()).andAnother()
w = do async console.log(await (await z).transmogrify()) the message sending part of the proposal would then be implemented by proxies on the returned objects. |
Why do these desugar to promise api calls instead of regular js syntax? The system for overriding behaviour in JS is proxies, and it seems really weird to disrupt that, especially using the Promise namespace, which seems very unrelated to MOP operations. Also, why is REST terminology being used for the prototype names? We generally use
set
in js, notput
.The text was updated successfully, but these errors were encountered: