Live data from Hacker News

Promises are not neutral enough

staltz.com

11–20 of 133 posts

Re: Promises are not neutral enough

#11
post #6
post #2

The alternatives look nice. There's just one requirement missing: streaming progress information to the listeners.

I think this completely changes what you have though, in a way that's no longer a primitive? You then have something like an async generator, which is like a fusion of asynchrony and sequence? Except generators are pull not push, so instead you have a promise that accepts a function that operates on a sequence? I don't know if this pattern is common somewhere, someone who does please explain!

In Haskell you can generate a list lazily. The last item in the list could be the final result-value, whereas the leading elements could be the progress information. Canceling a computation could be done simply by stopping to "listen" to the result (i.e. stopping the evaluation process).

I guess you could implement this in JS by having a promise-like structure which returns a tuple containing progress information AND a promise for the remainder of the computation. In a sense, this is similar to the generator approach.

One problem is if your program execs an external program. At what point should a promise kill the external process?

Re: Promises are not neutral enough

#12
post #7
post #4

This was a weird blog post to read. I think I agree on all of your points (Promises should be lazy[-ish], cancellable and optionally synchronous) but disagree on all of your proposed solutions. I do think `p = new Promise(fn);` shouldn't kick off the `fn` immediately. But that it should start right away in the next event loop. I haven't had issues with creating promise getters for repeatable calls. And think it organ…

One nice thing about "new Promise()" calling the function immediately is that if you are prepared to provide the value immediately then you don't have to return into the runloop, but probably the reason I'd give for why delaying the call would be a horrible idea is that the vast majority of the time the promise is going to do some minimal amount of setup work and then... return to the runloop (and if it isn't, I am g…

> if you are prepared to provide the value immediately then you don't have to return into the runloop

It might just my own mental model. But if I'm using a promise, it is a future value. So I don't understand why you would ever want to do that. Plus that's what Promise.resolve() is for. I'd expect them to act more like the now defunct setImmediate() function.

I concede that it may be more performant to do it this way as it results in less context switching, but I personally don't think performance should dictate a language's design of primitives.

Re: Promises are not neutral enough

#13

This may get me in hot water here but... I started working with JS promises specifically when they were barely available in a beta runtime. It took me over a year of working with them to really get a feel for them, now it's been far longer. That's because while you can "understand" the description and use it just fine, but a deeper comprehension and intuition takes much more time. I experimented a lot and insisted on…

Post sounded like they picked up promises over the weekend and didn't like how it broke their C# mold.

Quite a few points didn't make any sense or simply showed misunderstanding around how and why promises are what they are.

> Eager, not lazy

Why does this even matter? It's an implementation detail that optimises for performance.

The outcome, eventual resolution, is all that really matters.

> No cancellation

These are not tasks, and covered elsewhere in the thread: I/O.

> Never synchronous

Its a promise, so that doesn't really make sense to complain about.

Alas it is solved with Async/await (which is just promises under the hood.)

> then() is a mix of map() and flatMap()

This one I can concede as it would be useful to have the option, or at least have them exposed.

I suspect then was simply kept because that's what bluebird or whatever it was at the time did.

Re: Promises are not neutral enough

#14
const myJob = { run: () => fetch(... is too long? Eager is easy to make lazy. While the opposite is also true, it means a superfluous run. It is worse, semantically speaking. I'd argue that eager is more general than lazy.

Also, cancellation is yet another state and it's hard to generalize especially when you don't have threads.

Promises should always be async because you'd want the result to be consistent. If I'm returning a promise and you are depending it to be sync, that means it weakens my flexibility. It makes the code harder to reason about.

Re: Promises are not neutral enough

#15
I have a feeling the author doesn't understand Promises well. In my opinion, they are in fact designed poorly, but I don't see any problems with points the author describes.

He doesn't like that the callback is called immediately - but Promises just represent a result that will be available later and do not guarantee (and should not) when the function will be called. If you want to delay some function call, do it explicitly or use a delay promise.

In my opinion, the main problem with promises is broken error handling. They don't play well with exceptions. For example:

    var p = Promise(function (res, rej) {
        throw new RuntimeError("System is broken");
    });
This code will just ignore the error. While it is expected that the runtime error would float up and terminate the program - that is what runtime errors are made for.

This also makes writing tests more difficult because tests often use exceptions to indicate failure.

I have some ideas how to fix it (neither is perfect), but the comment will become too long.

Re: Promises are not neutral enough

#16
Neither lazy nor eager is neutral. Sometimes you want one, sometimes you want the other, and you can build either out of the other.

For promise cancellation, this has been talked to death, but in short, making any function preemptable at any point in its execution makes writing correct code much much harder. As an example, I've got an API that takes independently cancellable requests. Multiple requests often need to calculate the same thing, so there's a cache. Any given promise in the system might be downstream of multiple requests. If cancellation is built into promises, how do I express how cancellation should propagate through the tree of promises?

A C#-style cancellation token API, orthogonal to promises, is simple, easy to build, and easy to understand.

Re: Promises are not neutral enough

#17

I think the author wants promises to represent computation, whereas they represent predetermined (i.e. single-shot) events. He mentioned C# Tasks, which do mainly represent computation, but in some cases Tasks are also used as events and this gets confusing as hell. I've worked with C# Tasks and hope that MS once cleans this up and builds the stuff on promises instead. Note that the C# language construct uses the awa…

Actually, cancellations can be useful to prevent wasting resources on useless computations. Imagine, if you have 2 threads doing some computations that will be later merged. If one thread fails, it makes no sense to continue executing other thread. That is where cancellation can help - but it should be thoroughly designed, not hacked like they usually do it in Node.JS.

Re: Promises are not neutral enough

#18
post #7
post #4

This was a weird blog post to read. I think I agree on all of your points (Promises should be lazy[-ish], cancellable and optionally synchronous) but disagree on all of your proposed solutions. I do think `p = new Promise(fn);` shouldn't kick off the `fn` immediately. But that it should start right away in the next event loop. I haven't had issues with creating promise getters for repeatable calls. And think it organ…

One nice thing about "new Promise()" calling the function immediately is that if you are prepared to provide the value immediately then you don't have to return into the runloop, but probably the reason I'd give for why delaying the call would be a horrible idea is that the vast majority of the time the promise is going to do some minimal amount of setup work and then... return to the runloop (and if it isn't, I am g…

No, you won't get the result immediately anyway because then() callbacks are called only on next event loop iteration. This protects from overflowing the stack, but might have small impact on performance.

Re: Promises are not neutral enough

#19
I don't know. André Staltz is a great programmer, but I can't help but think what seems "opinionated" to him about promises boils down to the fact that they don't perfectly match certain quasi-ideological preferences he has about async programming, at the expense of all other concerns. As he states at the end, promises still work, you can get things done and everything is fine. But the part about them being opinionated I just can't get behind.

In fact, if promises worked the way he wanted them to, it would hurt the ecosystem in every category he mentions. Lazy promises would cease representing a single value, and be un-cacheable. Promises that didn't flatten inner promises would create endless confusion and ambiguity over "onion-promise" scenarios. Sometimes-synchronous promises would introduce subtle and sometimes catastrophic runtime ambiguities (aka "release zalgo"). Even cancelable promises would raise thorny issues regarding whether promises are intended to be multicast or unicast, which is a problem the current design side-steps entirely.

Re: Promises are not neutral enough

#20

This may get me in hot water here but... I started working with JS promises specifically when they were barely available in a beta runtime. It took me over a year of working with them to really get a feel for them, now it's been far longer. That's because while you can "understand" the description and use it just fine, but a deeper comprehension and intuition takes much more time. I experimented a lot and insisted on…

Cancelling the promise can be useful in fact to prevent doing computations that won't be used anyway. I tried to explain it in this comment: https://news.ycombinator.com/item?id=16386454
Post reply on HN