4 ms·
I don't agree with your first remark: what do you expect to be returned when you return a value not wrapped in a promise? The ambiguity is actually the auto un
by Guillaume86 11y ago
I don't agree with your first remark: what do you expect to be returned when you return a value not wrapped in a promise?
The ambiguity is actually the auto unwrapping of promises for subsequent then calls but I've yet to see a case where it's a problem (it's actually what makes the API clean looking when used).
For your last snippet, I don't see an array so I don't know what ordering you want to preserve (p always returns the same value so r will always be the same), if it's actually inside a loop, you should use Promise.all or Promise.map.
- tel 11y agoHe's stating the problem is dynamic typing... so the expectation would be a type error (!).
- andrus 11y agoI think the confusion stems from the fact that .then() acts like either .map() or .flatMap() depending on the return type. If .then() was just .flatMap(), you could expect an error if you didn't return a Promise (for example, reject with a TypeError). If .then() was just .map(), you could return a value of any type (for example, string or Promise<number>) and get back a Promise for a value of that type (Promise<string> or Promise<Promise<number>>).
- acjohnson55 11y agoActually, it's slightly more complex because if the result of the function passed to then were somehow a Promise<Promise<something>>, it would be flattened recursively so that the ultimate result is just Promise<something>. (Of course, due to .then's flattening semantics it's highly unlikely you'd have a Promise<Promise<...>> in the first places). The distinction between map and flatMap makes sense for, say, lists, because you often do want to keep the non-flattened structure around. From promises, I can't think of a reason why that would be desired. You just want to represent the final result after all necessary waiting is completed. I suppose a library could provide stricter map and flatMap for people who deeply care about this.
- adrusi 11y agowhat do you expect to be returned when you return a value not wrapped in a promise? Nothing that's a type error, it should throw a runtime exception just like all type errors in javascript, and it will show up in the debugger for the programmer to fix. The ambiguity is actually the auto unwrapping of promises for subsequent then calls but I've yet to see a case where it's a problem (it's actually what makes the API clean looking when used). I'm not sure I quite understand what you're referring to, but I think you mean the fact that you can chain then calls Promise.resolve(5) .then(x => Promise.resolve(x + 5)) .then(x => Promise.resolve(x + 5)) .then(x => { // x == 15 }); This is totally sound behavior. The simplified signature of `.then()` is then :: Promise a -> (a -> Promise b) -> Promise b This makes `.then()` the `bind` function for the Promise monad. As a refresher for people who don't think about monads much: (>>=) :: Monad m => m a -> (a -> m b) -> m b While on this tangent, I'll note that `Promise.resolve()` is the `return` function for the promise monad: return :: Monad m => a -> m a Promise.resolve :: a -> Promise a For your last snippet, I don't see an array so I don't know what ordering you want to preserve It's a contrived example demonstrating how switching based on whether the return value is a promise can make hard to detect bugs. It's hard to come up with a short example for this because strange values turning up where they don't belong is a property of large, dynamically typed systems. So yes, the example doesn't use all the best practices.
- Guillaume86 11y agoWell I can't really see any benefit to force the wrapping all returned values in promises without a proper example. The then() signature can be expressed in typescript and I suppose in alternatives like flow (using the union type): https://github.com/borisyankov/DefinitelyTyped/blob/master/es6-promise/es6-promise.d.ts https://github.com/borisyankov/DefinitelyTyped/blob/master/e... .
- tel 11y agoSure, you can represent it that way, but it needlessly complicates the semantics of `then`. If they were merely monadic bind then it'd easily be 1/20th as confusing. The "overload everything every which way and assume that people are really sensitive to the differences" strategy just begs misunderstanding. Monadic bind as the core and basis of your API is fantastic. It is exactly enough and no more than you need to define effectful sequencing semantics and, if you like, you can build everything atop it. And, honestly, you do anyway. But right now the design obscures the simple basis technology in order to have heaps of overload magic.