Hacker News new | ask | show | jobs
by magnushiie 3053 days ago
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 awaitable pattern (GetAwaiter method) instead of tasks - awaitables are actually pretty similar to promises.

1. Eager, not lazy - I think it was a mistake for the promise constructor to take a function, and in that way lead the users to believe the promise represents a computation. Creating a pair of promise and future (the latter as the producer side, like in C++) would be much cleaner. I disagree that lazy would be more general, you can simulate lazyness with functions, but you couldn't eliminate the performance cost of creating the unnecessary closure with a lazy solution. Regarding getUserAge - the common case for that function would be to take the user ID as the parameter (and hence would be lazy by construction), the parameterless version is a special case.

2. No cancellation - cancellation is much better represented with cancellation tokens (even C# Tasks cancel with cancellation tokens, so does fun-task mentioned at the end, though in non-composable way) - you cannot build a generic solution that can cancel the right computations. With cancellation tokens it's clear what cancels what.

3. and 4. (as well as being allowed pass non-promises to places where only promises make sense, like Promise.all and await) are unfortunate accidents that make typed environments (e.g. TypeScript) harder to work with but are not that important as 1 and 2.

2 comments

As it is, the fact that the promise initializer function is called immediately is a god send. If I had a dollar for every concurrency race-like condition that has prevented..

Constructor doesn't just take a function, it takes a closure if you so choose.. A closure that has immediate access to resolve and reject and doesn't have to worry about other code paths access its enclosed vars first.

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.
I was not saying cancellations are not useful, I was saying cancellations are better handled explicitly via cancellation tokens (which compose perfectly, unlike computation based cancellation).