5 ms·
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
by _greim_ 9y ago
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.
- spion 9y agoThis has nothing to do with it. I love promises but they are truly limiting. Here is an example of how promises limit the power of mobx https://twitter.com/spion/status/958906847385341952 https://twitter.com/spion/status/958906847385341952 Another example relevant in node is continuation-local-storage (equivalent to threadlocal storage). Implementing it on top of generators or other "chainable / thenable" abstractions is trivially easy. Implementing it on top of native promises and async/await is impossible without deep hooks into the platform. More examples here: https://spion.github.io/posts/es7-async-await-step-in-the-wrong-direction.html https://spion.github.io/posts/es7-async-await-step-in-the-wr... (see the second part) We should've paused on async-await and waited for jhusain's compositional functions: https://github.com/jhusain/compositional-functions https://github.com/jhusain/compositional-functions In the meantime generator based libraries would've properly explored the whole breadth of power that co-routines can give you, creating cowpaths to be paved by TC39. Promises make trade-offs, and they end up with a design that is generally good and can be used well in some number of situations. But not all. Not nearly enough to get first class syntax support that makes them privileged over all other solutions.
- matharmin 9y agoGorgi Kosev's post highlights a very nice use case for generators (database transactions). However, in all my JavaScript over the last few years, that is the only good use case I've found so far in my code base for generators. In all other use cases I've come across, async-await works just fine, and has a much nicer syntax to work with.
- spion 9y agoI elaborated that case in the most detail, but there are many other problems that generators solve mentioned in the blog post. Another very common one is getting the current user that initiated the request (or maybe their session), which you need to pass around to all your functions/classes. What if you could simply `yield getCurrentUserSession` and the engine which ran the toplevel generator returned it back to you? jhusein's compositional functions solved the syntax issue.
- fiatjaf 9y agoMobX is horribly opinionated, a monstruous abstraction of spaghetti, and you're saying Promises limit it?
- spion 9y agoMobX is the most powerful front end development library on the market right now. It single-handedly solves the cache invalidation problem in a performant way, and its pluggable into any framework. And yes, promises limit it.
- mathgladiator 9y agoHow does one measure power? What market?
- spion 9y agoBy actually using the thing being criticised instead of giving it the middlebrow dismissal. The "market" of application state management libraries.
- staltz 9y agoHi. First I'd like to comment that I wrote that blog post literally quickly because I just wanted to convert an informal Twitter thread into a more shareable and digestible format, so I didn't take the time to make it "hackernews comment resistant" if you know what I mean. On opinionated choices: I try to base that on mathematics. When it comes to async programming, that means equational reasoning and following some basic properties such as composition, associativity, left identity, right identity, etc, see https://github.com/fantasyland/fantasy-land https://github.com/fantasyland/fantasy-land . These would be neutral because math is often neutral. For instance, if intelligent aliens exist, they probably figured out the circle just like we did. On ideological preferences: there isn't anything free of ideology, so yes I am motivated by some ideology, not unlike influential members of TC39. There, you'll often find opposition to functional programming ideas, even though JS was originally designed with influences from Scheme, and allowed functional programming better than, e.g., Java at the time. See these TC39 notes, for instance: https://github.com/tc39/tc39-notes/blob/master/es8/2017-09/sep-26.md#11iva-first-class-protocols https://github.com/tc39/tc39-notes/blob/master/es8/2017-09/s... FP ideas are usually opposed because TC39 proposals are driven by concrete use cases, and FP is all about abstractions. FP ideology is that abstractions are good because they accomplish abstract goals, not a single particular concrete goal. That does not play well with the use-case-first process at TC39. So, ideologies. On "it would hurt the ecosystem": I think by now a lot of people from different language communities recognize the success of RxJava/RxJS/Rx.NET, and it tackles all those complications you mentioned, but for even more complex use cases, because it handles multiple values over time. I'm not arguing that Rx is a silver bullet, I'm just saying the Rx community has first hand experience with solving and teaching solutions to the problems you mentioned in the second paragraph and it's nowhere near "catastrophic".
- acjohnson55 9y agoWhat if we just make a Task that works the way you want Promises to work, and `run`ning it returns a Promise?
- lilactown 9y agoThe way that promises are implemented actively hurts the ecosystem. Trying to e.g. create a sound typing of the Promise API is really, really hard because of it's auto-flattening nature. This severely hampers languages like TypeScript, Flow & ReasonML that build on top of JavaScript.
- matharmin 9y agoIt may have been hard, but TypeScript seems to have managed quite well.
- woah 9y agoI have to agree. This blog post comes from a place of judging what is "better" by some arbitrary abstract metrics (hint: the author's own library wins this contest). It doesn't consider what programmers use them for. Promises are meant to semantically (and with async/await, syntactically) resemble a function call as closely as possible, while minimizing confusing errors. The author's "improvements" would ruin this. If I need a bunch of features that a promise doesn't provide, like cancellation, I will write something to do it manually with callbacks. This is far less than 1% of async calls though.
- naasking 9y ago> This blog post comes from a place of judging what is "better" by some arbitrary abstract metrics Or you could consider the possibility that they aren't arbitrary at all. Perhaps these properties are well motivated by, for instance equational reasoning, which is a cornerstone of extensible and maintainable programming. > Promises are meant to semantically (and with async/await, syntactically) resemble a function call as closely as possible, while minimizing confusing errors Why? What purpose does that ultimately serve given we already have functions? The whole point of an abstraction is to provide sophisticated semantics to do an important job you would otherwise have to do by hand.
- squiggleblaz 9y agoAlthough I don't like most of his alleged improvements, surely a separate map/flatMap would be more like function calls. If I write function foo(v) { return function () { return v } } const fv = foo(4) then I expect fv will be a function, not a number. In that respect, I think the choice to make `then` flatten was a poor decision that makes it more confusing for people who don't really take the time to understand. Such people don't realise it's confusing: they simply notice it's usually convenient; but they're inhibited from drawing the correct analogies. But as for the rest. Yeah, it's just arbitrary and weird. Maybe we should make integers all arrays lazy by default too?
- noobermin 9y agoWhenever some calls something else opinionated, you have to be aware they probably mean it just doesn't square with their opinion.
- strken 9y agoI think there's a similar but stronger form of opinionation where a choice prevents you from ever implementing something. In this case, not being able to synchronously resolve a promise prevents you from using them in certain ways. You can attach flatMap to the prototype or build a better way of doing cancellations, but you'll need to make additions to the language itself to turn a promise synchronous, which is what await/async were all about. Having said all that, the bar for promises isn't set by RxJS, it's set by callback(err). EDIT: also, promises were very much discovered. They're an opinionated solution to the very specific problems of callbacks. They're chainable because of callback hell. Errors propagate because that's a problem with callbacks. Their execution is always delayed because callbacks made it hard to reason about execution order. They don't handle cancellation because callbacks don't handle cancellation.