Side Effects vs. Promises
blueskyonmars.com
blueskyonmars.com
If you write your promises code not to cause explicit side effects - it won't and you get pure code.
The fact you have (controlled!) side effects is the whole purpose of the IO monad. You can't avoid side effects or your program wouldn't do anything, a promise keeps the side effects in a box (the promise) and lets you code using boxes so that your code is purer. Of course, not all your code can be _actually_ pure because all code needs side effects.
The FUD about async/await is even stranger. JS _has_ async/await, it already shipped in Microsoft Edge (IE) and it's coming to other browsers. It is based on promises (just like it's based on Tasks = Promises) in C#.
The fact people talk so much about this without learning the topic is amazing. I'm genuinely disappointed with the quality of discussion in HN over these topics lately.
Monet is also a bad implementation of the IO monad in JS, in fact it's not an implementation at all. Here is an issue I opened there a while ago: https://github.com/cwmyers/monet.js/issues/25
[1] up to the fact `.then` does both `fmap` and `>>=` through overloading based on the return type. Seriously, if you remove the exceptions and the fact you can return an unwrapped value it's `Promise a -> a -> Promise b -> Promise b` for then's signature (the Promise a being `this`, the a -> Promise b` being the handler and the return value being itself).
If you look at all the examples online for `IO` [2] they all translate 1-1 to promises just fine :)
[1] : http://blog.sigfpe.com/2008/12/mother-of-all-monads.html [2] : for example http://adit.io/posts/2013-04-17-functors,_applicatives,_and_...
The point about continuations is also a very interesting one, but I think again, stems from the same idea: Almost any monadic interface can be simulated with continuations.
But of course we're talking about IO... so my mental model is just that: mine and mine alone, really.
The way I've seen promises used in JS is always in this pseudocode form:
- initiate something side effecty (making an HTTP request, for example)
- resolve the promise once the value is ready
Is there something you have in mind for how we'd write promises-based code without side effects in JS?
So given the same input the same function will always return the same output. If you have a function that asynchronously computes a random number - it won't return different numbers and will always return a promise for a random number. It will never be observable that being called with a different input it produced a different output (as long as you don't mutate global state or anything like that).
In Haskell, IO is implemented in a way that causes side effects at the platform level. If there are no side effects there is nothing going on and the program is a no op after all :) Monads like IO are about _limiting_ side effects and _controlling_ state.
In Haskell, the lack of side effects is by the fact IO is provided by the platform. There is no fundamental difference between Haskell's `getLine` and the DOM's `fetch`, both return a boxed value.
> In Haskell, the lack of side effects is by the fact IO is provided by the platform. There is no fundamental difference between Haskell's `getLine` and the DOM's `fetch`, both return a boxed value.
In his talk about "effects"[1], Chris Armstrong also talked about making testing easier in Haskell, though I paid less attention to that part, to be honest.
`fetch` returns a promise, but calling fetch causes the side effect to occur immediately. I don't know if that's how `getLine` works in Haskell. If I want to test code that calls `fetch` without an HTTP request actually hitting the network, I need to put in a mock `fetch`.[2]
Or, if there was another return type that put the side effect in a box that the platform handles later (or not at all, in the case of a test), that seems like a win.
[1]: https://www.youtube.com/watch?v=D37dc9EoFus
[2]: another option, pointed out on Twitter, is that a promise (either from the fetch or from the test) could be passed in to the code under test. That seems less pleasant but requires no new machinery.
You couldn't implement `fetch` yourself without platform APIs and you certainly couldn't do it in JavaScript without the DOM. The second suggestion you pointed (from Twitter) is exactly what you'd do in Haskell (you'd pass an IO from somewhere else). You can call it "pass an effect" if you'd like but it's the same thing :)
Outside of those, I don't know what the story is.
1. Call the function with async { } block and have it return a computation object
2. Start that computation object in three primary ways:
a. On another thread, then wait (non-blocking) on it to finish
b. On another thread but don't wait for it to finish
c. On the current thread and don't wait for it to finish
There's a lot more details but that's going to cover probably 95% of the use cases.My takeaways from it are:
a. Super easy to write code for it that's easy to read
b. Really hard to fuck it up
In my opinion, it's superior to the model that C#/VB have ... and pretty much every other language I've tried async support on. Have yet to use Haskell for it.
Both haskell and ocaml currently require you to use do-notation to write async code. I'm really looking forwards to algebraic effects landing in ocaml though because with that they will be introducing delimited one-shot continuations as part of the core language.
Promises are not perfect either, but at least you can inspect them and thanks to new developer tools you can do it much easier.
[1] https://github.com/petkaantonov/bluebird/blob/master/API.md#... [2] https://github.com/petkaantonov/bluebird/blob/master/API.md#...
Is there something like this for event systems?
I mean, if I send stuff to the server and wait for it to answer, promises work really well.
But what about things like onClick? The promise can only resolve once.
I've also personally been using Rx and RxJS a lot and have been enjoying it a lot over the past few years. Observables and async iterators are both features that are on standards track for the language. See https://github.com/zenparsing/es-observable and https://github.com/Reactive-Extensions/RxJS
Every time I use promises I find that I lose errors and it takes hours of adding console.logs all over the place until I find the place with the error some nested promise is hiding.
Here is a talk I gave about adding it last June: https://www.youtube.com/watch?v=LGpmUyFnyuQ
Personally, I recommend you use a faster richer userland library like Bluebird which has stronger unhandled rejection tracking.
Edit: I mean ES7 async, not async.js (even though it's a great library)
See go or haskell for example.
I agree that it's not optimal, but the alternative (implicit IO) has its own share of pitfalls either. The async code that gets produced with modern JavaScript or Python is pretty easy to follow.
Elm does look very nice. Not sure if I'd get the team on board with that kind of change ;)
> write unit tests for your code without mocking, by specifying the expected content, results, and order of side-effects performed by a function
No mocking? This is absurd. Some functions rightfully hit databases and the network. It either gets tested the right way, with mocks; the wrong way, with actual network calls; or not at all, as the author seems to suggest. Mocking belongs in some part in unit tests
In practice, that functionality basis can be far tinier than the set of things which would require mocking normally. This is a big win.
Also in practice you may want to make the functionality basis larger than it need be semantically because this can be a performance win.
This is one of the big benefits of FP and pure functions really. I'm sure there would be practicalities that get in the way of doing this cleanly for all code, but it can go a surprisingly long way. The idea is to write a completely pure core and restrict input/output to be through a few small and obviously correct functions.
Some people would insist that the closure is a mock, but otherwise this is correct, using closures in this way does help isolate one's tests.
The callback pyramid madness has been traded for a simple and flat waterfall[2].
The constant .then and .catch when working with promises naturally makes a lot of people uncomfortable, and on top of that the async library provides a plethora of other collection manipulation and control flow utilities.
Frankly I think managing side effects should be abstracted away, and furthermore I cannot wait for C#-like async/await to become first-class citizens in the JS world.
we're mixing up 2 different things here, the async package and the C# like async/await feature native to javascript. The async package while popular is certainly not more popular than promises.
Well cancel your signal because native browser APIs are returning promises:
https://developer.mozilla.org/en-US/docs/Web/API/MediaDevice...
What (js) planet are you living on ? async package certainly has it's place, but the fact that promises are object you can pass around make them more useful than any async package.
> Frankly I think managing side effects should be abstracted away, and furthermore I cannot wait for C#-like async/await to become first-class citizens in the JS world.
Well too bad, because async/await will work with promises.
And I quote the blogpost :
> In practice, returning side effects rather than performing them and returning promises can increase the size of the “functional core” of your application, which is a win in my book.
Which is exactly what I'm saying.
Well too bad, because async/await will work with promises.
and promises are built on callbacks at the lower level.I just don't really get these callback-intolerant people's averse reaction towards this construct when it's literally all over the place and those new abstractions are there to conceal them which is a good idea by the way but not to extinguish them completely as they might hope or believe.