
JavaScript Promises Discussion: Make Them Monadic? (2013) - jashkenas
https://github.com/promises-aplus/promises-spec/issues/94
======
turbohz
This is an old discussion (which I had followed for years). The proposal,
afaik, was never accepted into Ecmascript.

So we ended up with half baked Promises.

In a particular nodejs project I worked on, I overrode the native Promise
implementation with the one provided by Pacta, but was not ideal (promises
returned by other modules where native, ...)

Not doing nodejs work anymore, but I'm still rather disappointed about how
Ecmascript promises were ultimately delivered.

~~~
Lazare
Yeah. Native promises are _usable_ , and they're okay...

...but with only a few small changes they could have been much better, and
it's frustrating to see proposal to make them better back when that was an
option denied out of hand with such arrogance and (to my mind) lack of
understanding of what was even being discussed. The linked thread of comments
has _not_ aged well over the years.

(And it's doubly frustrating now that the (excellent!) async/await syntax has
now been built on top of it. What a wasted opportunity.)

------
vinylkey
Fun fact: the JS library Fantasy Land [1] got its name from that discussion
[2].

[1] [https://github.com/fantasyland/fantasy-
land](https://github.com/fantasyland/fantasy-land)

[2] [https://github.com/promises-aplus/promises-
spec/issues/94#is...](https://github.com/promises-aplus/promises-
spec/issues/94#issuecomment-16176966)

~~~
rmrfrmrf
Another fun fact: the guy who mocked devs asking for monadic Promises later
"championed" and subsequently withdrew the TC39 proposal for Promise
cancelation, presumably after realizing that it's impossible to shoehorn into
the current spec cleanly.

~~~
shados
Having followed the promise cancellation proposal pretty closely, especially
when it came to a close, it sounded more like he got sick of the pushback
(specifically mentioning push back internally at Google) if my memory serves.
I won't pretend to speak for him, but I don't recall him withdrawing the
proposal because he didn't think his solution was correct. He just didn't want
to deal with the detractors anymore.

Of course, it was a solution to a problem he created, so... (to be fair, the
JavaScript world was very different then than it is now, in the same way ES6
classes would probably work very differently if they were designed today)

------
nawgszy
I am surprised to see so much venom against Promises expressed here. I am
young, but I began coding (as a profession) just when Angular 1 was popular
and I remember callback hell was a real thing.

A few years later, I use Promises a lot, and they work really well. The way
errors bubble is logical and easily controlled, it's almost impossible to
throw an unhandled promise exception, doing 'parallel' tasks is easy with
```Promise.all([])```, and there's pretty limited complexity with the way a
Promise always returns a Promise.

I find the simplest way to use them is to define a class that has a few data
properties you'd like to track.

    
    
      class Handler {
        constructor() {
          // shared variables can be set / reset here
          this.defineInitialState();
        }
    
        executeAction() {
          return (
            this.promiseFn()
            .then(() => this.anotherPromise())
            .then((passedArgument) => this.promiseExpectingArgument())
            .then(
              // success case
              () => this.successHandler(),
              (err) => this.errorHandler()
            )
          );
        }
      }
    

It's modular and you know what to expect (it's always a promise!). Sure, it's
imperfect, but I think its weakly opinionated simplicity is a good tradeoff.
After all, it makes no distinction of whether any of the functions in that
chain were synchronous or not, and that's a nice thing to know. It also makes
testing with dummy sync functions in place of actually asynchronous ones a
0-effort integration.

I don't know about this async / await keyword stuff, and if you have to wrap
it in a try/catch block, that's unfortunate but also seems like it's not the
end of the world. After all, isn't the Go language constantly requiring you to
say "if err != nil <your code>"? Explicit error handling isn't even a bad
thing.

Anyways, this is just my opinion, it's fair to have your own, and maybe other
languages handle asynchronicity more gracefully, but from what I've seen this
is a clean way to wrap async OR sync code in a context that makes it always
behave predictably and readably.

~~~
shados
As already mentioned, they're a lot better than callbacks (well, for certain
cases. There are still places where callbacks are better).

The problem is that this is a field that has been heavily studied, and there
are great solutions to this problem that also solve countless other problems,
and interop well with each other. The way promises work, they solve that ONE
problem but throw away the rest.

If you have the choice between 2 mostly equivalent solutions to solve a
problem, but one of the solutions also solve 10 other problems with
essentially no drawback, why would you choose the former?

This is probably already linked in this thread somewhere and is also probably
was prompted someone to post this old issue to Hacker news, but this is a good
explanation of the problem:

[https://staltz.com/promises-are-not-neutral-
enough.html](https://staltz.com/promises-are-not-neutral-enough.html)

~~~
todd_wanna_code
> There are still places where callbacks are better)

Like? I am genuinely interested in knowing the drawbacks of promises and
places where a callback like structure is more favourable. By the way, I am
not contradicting you, just trying to learn.

~~~
imtringued
A promise can only be activated once. You still have to use callbacks for
buttons and other things that can be activated more than once.

------
rockymadden
For those looking for monadic Promises, I’d suggest taking a look at Fluture
([https://github.com/fluture-js/Fluture](https://github.com/fluture-
js/Fluture)). It’s a wonderful library and with do-notation, ability to work
with callbacks, nodebacks, and Promises, I haven’t looked back. It also has
adheres to Fantasy Land, Static Land, and has defintions for santuary-def.

~~~
dahart
> It also has adheres to Fantasy Land, Static Land, and has defintions for
> santuary-def.

I think I understood a couple words in that sentence, like "it" and "has". :P

Looking up fantasy-land, I found [https://github.com/fantasyland/fantasy-
land](https://github.com/fantasyland/fantasy-land). I would like to better
understand these monads everyone is talking about.

But, just to be super honest -- and possibly completely wrong -- the
terminology is _really_ off-putting. At a glance it just feels super complex,
academic and completely divorced from practical coding. I get vibes of
enterprise java class hierarchies looking at this stuff.

I hope I'm wrong, and I really am interested to learn more about it, but I can
see from the OP's linked thread that I'm not alone feeling this way. It's not
at all clear why I should be thinking about my JavaScript algebraically at all
times, or what the practical advantages are. After decades of coding, I'm just
getting more alergic to complexity, and this feels like complexity.

What are some good online resources that might help me change my mind and see
the light?

~~~
Nadya
"Once you understand monads, you immediately become incapable of explaining
them to anyone else” Lady Monadgreen’s curse ~ Gilad Bracha"

If you'd like to go down a rabbit hole of category theory look up the phrase
"A monad is just a monoid in the category of endofunctors, what's the
problem?" \- a fun quote that a lot of monad explanatory tutorials will quip.
Not that it will help - because anyone writing a monad explanation already
suffers from the first quote: they're incapable of explaining them.

I had read 30 or 35 different monads-for-Javascript
tutorials/guides/explanations before I finally _thought_ I grokked it. None of
them have helped and I'm still not sure my understanding of them is correct.

~~~
ngcazz
Because the point is mostly lost on the unrelated analogies most tutorial
writers use. A monad is a mathematical construct. Trying to explain them in
terms of what makes sense to you, because your analogy results from your
understanding, isn't likely to be more helpful than outright accepting what
they represent, mathematically speaking, then putting that to use in your
code.

~~~
rmrfrmrf
A monad is most simply described as the quantum superposition of the state of
being (or not being) a burrito.

------
moomin
Such a dumb discussion. One guy saying “Here’s a proven design”, someone else
calling it “Typed Language Fantasyland”.

~~~
baristaGeek
It's not a dumb discussion at all. Callback hells and managing threads
synchronously/asynchronously as desired are a big deal.

------
mikewhy
I'm confused, and am not very knowledgeable about FP (though I am very
interested in it).

Can anyone explain how the 3 bullet points in the issue aren't already in
Promises?

> Promise.of(a) will turn anything into promise.

This just looks like `Promise.resolve(a)`

> Promise#then(f) should take one function, not two.

That's applicable, but you could try limiting yourself to only using one
argument.

> Promise#onRejected(f): move onRejected to prototype instead of second arg.

`Promise#catch(f)`?

~~~
tel
The issue with `of` is that it special cases when `a` is already a Promise.
Promises try hard to not be nested (a promise of a promise) but that nesting
is critical for algebraic properties.

The then issue is multifarious. On one side, splitting the two uses makes the
algebraic justification for then more clear, but it's not a big deal. The
_real_ issue is that `then(f)` does different things when `f` returns a
Promise. This breaks in the same way that `of` did—you need to be able to
discuss nested promises.

~~~
BigJono
That just raises more questions. Can anyone here give a concrete example of a
real world problem that is more cleanly solved with these changes to the
Promise spec?

There's a lot of talk about FP and type theory here, and none about actual
work. To me, all this stuff is still in the "cool to play around with at home"
category. But until it affects day to day dev work, there's a whole set of
people that aren't going to give the slightest fuck.

~~~
pka
> But until it affects day to day dev work, there's a whole set of people that
> aren't going to give the slightest fuck.

That's a seriously toxic attitude to have.

People are using monads and other FP concepts daily to simplify "day to day
dev work" (here's an example [0].) The fact that it's more or less mainstream
to write off a concept because it sounds "academic" is worryingly anti-
intellectual in a profession that is allegedly based in analytical thinking.

> Can anyone here give a concrete example of a real world problem that is more
> cleanly solved with these changes to the Promise spec?

There are some in the linked github thread (which had to be reposted
repeatedly until people actually stopped and read them, btw.) It's about being
able to write DRY code that abstracts over not only promises, but anything
else that forms a monad, like arrays, optional values, and so on.

[0] [https://github.com/facebook/Haxl](https://github.com/facebook/Haxl)

------
tyingq
I wonder why we have to resort to terms like monadic, immutable, orthagonal,
etc, in our field so often. I feel weird and elitist using these terms when
more common ones suffice and are understood by my customers.

~~~
rmrfrmrf
Would you call a car mechanic elitist for talking about carburetors and
alternators?

~~~
tyingq
I don't feel like that's a great analogy. "Fuel cell" vs "gas tank" is closer.
There's not a simple one or two word commonly used equivalent for carburetor.
I'm not opposed to specific terms when there aren't simpler alternatives.
"Exponential", for example, doesn't bother me. Orthagonal, though is
irritating. Why not just say "unrelated" or "not correlated", etc.

------
marcosdumay
WebAssembly can't come fast enough.

Really:

> @pufuwozu can you show with a concrete example why you can't write the
> example code you posted with promises?

Why couldn't him just give a concrete example of what he was claiming that was
impossible?

------
odammit
I feel like I’m being promised a burrito.

~~~
hkailahi
A burrito is just a strong monad in the symmetric monoidal category of food,
what’s the promise?

~~~
odammit
That maybe I’ll get a burrito.

------
yuchi
Seeing Jeremy resurfacing old threads brings me memories.

Anyway this was a nice thread to follow while it happened.

------
pier25
Honestly, I think Promises with async/await and try/catch are good enough for
a lot of use cases. Certainly lightyears ahead of callback hell.

IMO the next big thing will be Observables.

------
adreamingsoul
What about it?

------
MBCook
(2013)

~~~
dang
Thanks, added.

------
marknadal
I was never on the promise bandwagon because they never did anything useful
other than create hype with developers around using a more functional approach
- which is good, but promises themselves add no benefit.

For instance, people previously would do:

```

start(x => doA(y => doB(z => doC(end))))

```

When they could have just used named functions, with promises or not, it is
just that promises was hype that taught them good programming skills:

```

doA = x => doB(x)

doB = y => doC(y)

doC = z => end

start(doA);

```

As with promises:

```

start.then(x => x)

    
    
      .then(y => y)
    
      .then(z => z)
    
      .then(end)
    

```

The only real value of a promise now is being able to use `await`, which is
the real first-class language magic.

However, the future isn't even with promises, so there is no need to change or
modify them. The future is chain reaction programming, also goes by the name
of observables/FRP/stack-based-cocatenative-programming/railway-programming.

Programming Chain Reactions is great, because they can also downconvert easily
to `await`, so you get the best goodies of all the world.

We've implemented observable/FRP/chain-reaction programming as the default API
in [https://github.com/amark/gun](https://github.com/amark/gun) , it is really
quite pleasant language abstraction. However, FRP/etc. hasn't quite hit
"mainstream" hype yet, so developers do not know what they are missing out on.
Once you try it and it "clicks", you realize the future is truly bright. :)

------
redleggedfrog
Um, the problem here is Javascript. Don't use a cesspool of a language and you
don't have such banal conversations.

------
maximexx
> JavaScript Promises Discussion: Make Them Monadic?

No, just totally ditch them!

I can't help to hate Promises. Sometimes I have to work on a code base that is
completely baked with them, it's just a nightmare. With the stupid async await
implementation things haven't got any better.. Now they expect me to write
async calls in a try-catch block!?!

With JS I prefer to use simple callbacks until they come up with a proper
async await without try-catch and Promises bullshit. Callback hell happens not
because of the callback principle itself. It exists because it's too easy to
keep nesting functions. Most devs simply don't know how, or are too lazy, to
apply good patterns for using callbacks.

~~~
jey
> Now they expect me to write async calls in a try-catch block!?!

What do you mean? In my experience, the use of async/await leads to much
cleaner code for I/O driven tasks like querying APIs and databases. Yes, I do
have a try/catch at the top of the callstack to catch and log unexpected
errors.

~~~
vorpalhex
async/await worries me, not for abstract language reasons but because it hides
complexity in a way not friendly for junior engineers.

I imagine a lot of code that should be thought out and made parallel being
forced into a synchronous flow.

Note that promises aren't a ton better in this regard, and come with a ton of
confusion themselves. In short, async is hard.

~~~
jey
Promise.all() does a pretty good job of parallelizing tasks while maintaining
readability.

