Live data from Hacker News

Promises are not neutral enough

staltz.com

21–30 of 133 posts

Re: Promises are not neutral enough

#21
post #12
post #7

Earlier quoted context omitted.

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…

To use Promise.resolve you have to know whether the value is ready or not before you enter the promise, but you should enter the promise and then check that status. There are very few situations where Promise.resolve should be used: it is essentially a weird performance optimization for constant values. A basic example is something like reading from a network buffer: you call read, and there might be data immediately or you might have to wait; and in JavaScript the way you read might involve a callback, so it isn't even like "check buffer and then use Promise.resolve as awkward special case" but instead "call read passing callback; if data is already there the callback is called immediately". This also comes up while implementing stuff like "a set of values that consumers can ask for a value from; if the set is empty they will have to wait until there is a value".

Regardless, I legitimately believe the mental model of it not switching back and forth is fundamentally more correct for the primitive. The goal should also be that the abstraction has the same behavior and ordering semantics as doing it by hand. When you do it by hand, you essentially must run the code there immediately as otherwise there is no way to even run that code at all. Why would you ever want that code to be delayed? It frankly sounds like you are modeling Promise as if it meant Thread or something... a Promise is just a tiny adapter whose purpose is to change a wrap some setup code for accessing the value of a later event together into a common interface. A promise isn't doing the work: it is adapting the API of random models of doing future work (one-off callback APIs, random evented interfaces, etc.) to its own. Having this allows us to hack in (due to the lack of good monad support in most programming languages) async/await in a non-horrific way. If you want to do future work your first step should be to come up with a model for how your future work will happen, and then you use Promises just to do this adaptation, not to like, spawn some computation that will take time and which should happen later.

Re: Promises are not neutral enough

#22

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…

> you cannot cancel the actual (OS controlled) asynchronous operation

This is way too broad a claim. If I do something like:

  (sleep 1 ; echo "done") &
  kill $!
I'm pretty clearly "cancelling the actual (OS controlled) asynchronous operation". Now it may have done some sleeping at that point, and if you replace the sleep with something that has side-effects, then some of those side-effects may have occurred, but the operation is still being "cancelled".

Obviously it's not the case that every operation can be (meaningfully) cancelled, but some can. This is even more true when you consider that when you're using JS, you're generally way above the OS level. XMLHttpRequest has an abort() method for a reason: The underlying socket request may be queued up based on your browser's connection limits and, even if it's kicked off, your browser is going to have multiple opportunities to abort the process even if none of the underlying sub-operations can be preemptively cancelled.

Re: Promises are not neutral enough

#23

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 exp…

This is a fundamental issue with multitasking, in that an independent task will have its own stack, so errors can't propagate up the stack of the function that started the task.

e.g. consider this python code:

    def start_task():
      Thread(do_task).start()
What happens if do_task throws an exception? The exception can't propagate up from start_task because start_task may have returned when the exception is thrown.

At some point you have to join your threads, and you have to await/then your promises, otherwise there's no well defined place in your program for the exception to go.

Linters can help with this. tslint is one example, I believe it can give a warning for unhandled promises.

`p` will reject, any function that awaits p will reject. The error is that you've fired off an asynchronous task but you don't have any code that cares about the result of that asynchronous task (and the stack of any code that

Re: Promises are not neutral enough

#24

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 exp…

He literally talks about the work-arounds you can use to delay the function call in the article, and explains why you would prefer it to be default behavior.

Error handling is annoying, and this is (eventually going to be) fixed in Node.js. In the browser, you can add some listeners: http://2ality.com/2016/04/unhandled-rejections.html

Re: Promises are not neutral enough

#25
post #7

Earlier quoted context omitted.

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.

[deleted]

Re: Promises are not neutral enough

#26

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 exp…

This is a known footgun of promises. But if you are using async/await, uncaught error in the promise chain is the same as uncaught error inline.

Re: Promises are not neutral enough

#27
The analogies damage this article because they feel wrong. For example the "never synchronous" example is more like this:

You order a burger at the cashier window, then go to the pickup window. If the burger is already made, it's already at the pickup window when you get there.

The author wants a special case where if the burger is already made, they hand it to you immediately at the cashier window. This might seem more efficient, but both in the restaurant and in code it makes logic way more complex.

Re: Promises are not neutral enough

#28
post #23

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 exp…

This is a fundamental issue with multitasking, in that an independent task will have its own stack, so errors can't propagate up the stack of the function that started the task. e.g. consider this python code: def start_task(): Thread(do_task).start() What happens if do_task throws an exception? The exception can't propagate up from start_task because start_task may have returned when the exception is thrown. At some…

> otherwise there's no well defined place in your program for the exception to go.

I don't see the problem with that. Unhandled exceptions can occur at any place of your program.

I also don't see why the unhandled exception from the background thread cannot terminate main thread. Why not? That is how unhandled exceptions are supposed to work. Terminating the program is the optimal default behaviour for any error in my opinion. This way you won't miss them.

Re: Promises are not neutral enough

#29
post #23

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 exp…

This is a fundamental issue with multitasking, in that an independent task will have its own stack, so errors can't propagate up the stack of the function that started the task. e.g. consider this python code: def start_task(): Thread(do_task).start() What happens if do_task throws an exception? The exception can't propagate up from start_task because start_task may have returned when the exception is thrown. At some…

If you want to have a specific point to catch an exception, you could write something like this:

    def start_task():
        thread = Thread(do_task)
        thread.set_error_handler(SpecificErrorType, handler)
        thread.start()

Re: Promises are not neutral enough

#30
OK, we can't do threaded imperative programming because threads are expensive and people botch the locking. So we have callbacks where completion of some external event calls you back. Then you need closures so the callback has some state so it knows what to do when called back. Now you have a control structure problem, and need a state machine to decide what to do next. But most of the time you just want to do the next thing, so there's syntax such as ".then()" so you can write imperative programs again.
Post reply on HN