Open hexonaut opened 9 years ago
This was a pretty major debate in the js community for a while, since these type of then/pipe methods are essentially just rebranded versions of map and flatMap, using an asynchronous delay.
I don't have hard evidence, but my gut feeling is that javascript went with the approach you describe because most js devs are not used to dealing with cascading parameterized types like Promise<Promise<T>>
. There's no syntax for describing these sorts of things in js, and it could easily be confusing by just relying on runtime inspection to figure out exactly what you have within a given return value.
Haxe, on the other hand, handles type parameters like a champ. It eats them for breakfast. There's libraries that can manage mappings between types that enable a whole slew of different asynchronous programming styles, such as the "do" notation for monads. If you rely on a runtime behavior to coalesce promises to a a single "core" promise, then you're preventing those compile-time libraries from working properly.
The Either<A,B>
idea suffers the same problem... it would prevent functional composition since there are two parameters. This is one of the main reasons why I don't include an error type in the promise parameters.
Okay was just a thought. Definitely not a show-stopper for me. If you don't think this will work then feel free to close. Otherwise we can discuss more.
There was an epic thread on this over on the promises A+ project: https://github.com/promises-aplus/promises-spec/issues/94
I've been mulling over this for a while, so I want to give you the same chance to read up and come to your own conclusions. I'll leave this thread up a while.
I come down more on the side of wanting to treat promises more like a monad, which means keeping a distinct then/pipe (analogous to map/flatMap) approach. I think there's some advantages to doing that, since the entire promise chain can be described by the compiler. If you rely on the runtime to determine how to wrap/unwrap the promise, then you're defeating the compiler's ability to determine what the end result will look like.
On the flip side, Haxe has macros. It's possible that the "then" function for promhx could inspect the end results of a "then" function, and change to a "pipe" method if it determines the final result is a promise as well. However, this may slow down compilation... I'll need to check it out.
*note: I realize you're not advocating the runtime inspection approach. I thought that thread might be interesting since you're proposing a compile-time equivalent.
I haven't changed my mind much on this, I'll leave the bug active in wontfix for posterity.
Using other promise libraries in a language like JS is pretty flexible with the return type. Both then and error handling usually allow for either a value or a promise to be returned and will take the necessary steps. I find myself typing then a lot only to have to go back and change it to pipe if I happen to be returning a promise instead. Compared to a JS library counterpart I find I can fly through the promise logic much faster if I dont have to worry about this. The library just understands what I mean by the return type.
Now I'm not suggesting we type the return as Dynamic. Instead, we have a new abstract type in Haxe called haxe.EitherType which IMO will give us the best of both worlds. We can keep the strict typed-ness whilst boosting code speed.