The Promises/A+ spec is a disaster. There are two main things that are wrong with it.
- Combining
map
andflatMap
in a single method. - Assimilating objects which happen to have a
then
method.
The first problem is a minor pain point because it only affects promises. However, the second problem is a major pain point because it affects the entire JavaScript ecosystem.
Assimilation of objects which happen to have a then
method is such a terrible design that I conscientiously refuse to use the word "thenable". There is no such thing as a "thenable". There are only objects which happen to have a then
method.
Here are some of the things that people said about the assimilation of objects which happen to have a then
method, before it made it into the ECMA-262 specification.
-
robotlolita commented on Apr 11, 2013:
I'm okay with assimilating promises when you return a promise from a function in an
on{Fulfilled,Rejected}
, I'm not okay with assimilating things with athen
function. That it hasn't happened until now doesn't mean it will never happen (potential ≠ guaranteed). -
polotek commented on Apr 12, 2013:
Asking me to "fix my library" presumes that you've decided it's broken. It also presumes that I would agree with you that it's broken. My library works as designed for the most part. It's even got some tests on it (non-exhaustive as they may be). The point of contention here seems to be my use of the names "promise" and "then" in my design.
[…] I think it's a bit disingenuous to suggest to me and everyone else who ever uses the names "promise" and "then" that they should conform to A+. Even considering that I agree with what you're trying to accomplish here. There are several reasons for this. One is the presumption that I share your goal of interoperability. "until @polotek fixes his library, it can't co-exist with various promise libraries". Procstreams weren't designed to co-exist with promise libraries. No one has asked for it. I'm not sure how it has somehow become a requirement for your design, or how subsequently fixing that is my problem. Or maybe I'm misunderstanding your point. Are you saying that the promises A+ spec cannot and should not try to accomodate all
Thenables
in js? Because that I agree with. -
getify comment on Apr 12, 2013:
I consider it utter hogwash for anyone advocating for Promises/A+ that anyone else who has ever built a lib with a
then()
method now needs to change their API to make way for the freight train (called Promises/A+) that is barreling their way. Of all the blustering in this thread, and I just read the whole thing, it was that notion that completely "lost" me.There's (I'm sure) at least several libs in the pantheon of JS which have used the
then()
method name and they're not promises compliant (or assimilable by a promise in a way that wouldn't constitute surprise behavior by the person who was used to different behavior before introducing Promises/A+ into the mix).For reference, I have been doing "promise like" coding in JS for well over 3 years now. I am quite certain I was experimenting with these ideas well before Promises/A+ came along, and probably well before a lot (not all) on this thread were. And I have written promise libs using the
then()
method way before you decided to "reserve" that name.My current works in the promises area are asyncGate and asyncSteps, both of which abstract lightly the concept of promises, but provide simple(r) APIs for managing async code flow. Both of these libs were ALSO written before Promises/A+ came along. And both of them use
then()
. I'm not 100% positive, but I am pretty sure my libs are not A+ compliant and that they would behave in unexpected/surprising ways if incidentally assimilated by a A+ lib.I don't relish that my libs will forever be banished as incompatible (and broken by) from your way of viewing the promises world. But note: I am not the one who's creating the incompatibility, "you" are. My libs definitely wouldn't reject or misbehave if they saw one of your objects floating by. If you had any goal of trying to get any of us on the fringe on board, this tact was definitely not the way of doing so.
These quotes show that when the process of "assimilating objects which happen to have a then
method" was added to the specification, it broke a lot of existing libraries. That is, it was a BREAKING CHANGE. The tight coupling of promises with the then
method ensured that no other library could ever use the method name then
for any other purpose.
- Existing libraries had to come up with a different name to be Promises/A+ compatible.
- Newer libraries also had to square with this issue.
- There's even a custom eslint rule to prevent methods being named
then
.
All of these problems are caused by a wrong decision made 10 years ago. We shouldn't have to live with the consequences of wrong decisions for all eternity. Let's fix this by removing the process of "assimilation of objects which happen to have a then
method" from the spec.
Is this a breaking change? Yes, it most definitely is. However, it's a necessary change. To quote Malcolm X:
If you stick a knife in my back nine inches and pull it out six inches, there's no progress. You pull it all the way out, that's not progress. The progress is healing the wound that the blow made.
Let's not forget that the behavior of assimilating objects that happen to have a then
method was itself a breaking change. It was met with a lot of resistance from the JavaScript community, but added to the spec nonetheless. So, having another breaking change to rectify the mistake is not radical. It's progressive.
Once we agree that this is indeed a problem that needs to be solved, we can discuss the specifics of the solution. For example, we could talk about:
- Using a symbol such as
Symbol.then
to brand an object that should be assimilated. - Or, removing the assimilation of non-promise objects from the specification entirely.
Finally, I just want to leave you with one thought.
We don't have to live with mistakes. We can and should correct them.