7 ms·
Side Effects vs. Promises
- dclowd9901 11y agoSo what are we talking about here? Just wrapping side effects with a constructor so they're isolatable? You could just modify the Function prototype to mock a constant return for the same purpose, and it'd be completely transparent (no API littering the entire codebase).
- ihsw 11y agoPromises in the JS world have lost out to async[1]. 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. [1] https://www.npmjs.com/package/async https://www.npmjs.com/package/async [2] https://www.npmjs.com/package/async#waterfall https://www.npmjs.com/package/async#waterfall
- fiatjaf 11y agoAre you sure promises have lost to async? This is a crazy statement.
- agumonkey 11y agoI have no data, but ES7 plans to support async/await, and Python 3.5 just shipped with it. I find it a strong signal already.
- aikah 11y ago> I have no data, but ES7 plans to support async/await, and Python 3.5 just shipped with it. I find it a strong signal already. 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.
- lemevi 11y ago> I find it a strong signal already. Well cancel your signal because native browser APIs are returning promises: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia https://developer.mozilla.org/en-US/docs/Web/API/MediaDevice...
- agumonkey 11y agoConfusing mixed signals then.
- phpnode 11y agoasync/await is powered by promises, it's crazy to say that promises are going away, they're becoming an even more fundamental construct in the language.
- aikah 11y ago> Promises in the JS world have lost out to async[1]. 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.
- notNow 11y agoWell 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.
- msoad 11y agoI never liked the event oriented async programs. They are just harder to debug. Once you have more that a handful of evented object with couple of possible events you pretty much guaranteed to not know where to look for bugs. Promises are not perfect either, but at least you can inspect them and thanks to new developer tools you can do it much easier.
- coke12 11y agoWhy not just write events to a log, and then use the log to reproduce your bug?
- lkrubner 11y agoIf the events involve I/O then they are not deterministic. Even if you save every event to Kafka and then replay them, you may not get the same bug.
- inglor 11y ago:( https://code.google.com/p/chromium/issues/detail?id=526811 https://code.google.com/p/chromium/issues/detail?id=526811
- munro 11y agoBluebird makes debugging easy with long stack traces [1], and unhandled rejection detection [2]. Without the unhandled rejection detection, it's easy to get burned by forgetting to handle a rejection case, or use `.done()`. [1] https://github.com/petkaantonov/bluebird/blob/master/API.md#promiselongstacktraces---void https://github.com/petkaantonov/bluebird/blob/master/API.md#... [2] https://github.com/petkaantonov/bluebird/blob/master/API.md#promiseonpossiblyunhandledrejectionfunction-handler---undefined https://github.com/petkaantonov/bluebird/blob/master/API.md#...
- inglor 11y agoAs a bluebird contributor it's worth pointing out that while our stack traces are pretty sweet - unhandled rejection tracking exists in most modern promise libraries.
- saosebastiao 11y agoAll of the back and forth on async callbacks vs async/await vs promises makes me sad that more people haven't yet discovered async computation expressions as found in F#. It is easily the most intuitive and expressive form of declarative async computation out there. I wish F# were more popular so it's revolutionary concepts like this one would bleed their way into other languages.
- fennecfoxen 11y agoPity that it's got the Microsoft cloud hanging over it, then (Mono notwithstanding)
- Chattered 11y agoI haven't used F# much, but aren't computation-expressions just a Haskell like do-notation, which you get for free because the async type constructors are a monad? Ocaml and Haskell should have this, at least, with lwt and its syntax extension, and Async respectively. I'm not sure what the situation is in Scala, but they surely have something similar with their generic for-comprehensions. Outside of those, I don't know what the story is.
- edgyswingset 11y agoI'm not a Haskeller and haven't played with monads knowing they were monads, but async in F# basically works like this: 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.
- ufo 11y agoAsync is like having do-notation, but without having to convert your code to do-notation! Do-notation is nice but having a single notation for everything is even better. 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.
- krisdol 11y agoPersonally, I hate promises, but on topic > 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
- tel 11y agoThe idea here is that you can separate your "functionality basis" which does require mocking because it genuinely hits the database from "composed functionality" which operates through a pure, monadic DSL and eventually calls down to the functionality basis. 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.
- bonobo3000 11y agoIf you can write very pure code, mocking is not needed. For example, a function for a database call could return a closure of what to do given a cursor into the database, or a SQL query which can be tested. The side-effecting functions themselves would just create a connection to a db or network host and do exactly what is prescribed in the request, making them simple enough to not need to unit test. 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.
- lkrubner 11y ago"return a closure of what to do given a cursor into the database" 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.
- 11y ago
- arianvanp 11y agoI've recently decided that all this async and evented stuff is just too hard to reason about. A proper language should have (lightweight) threads if it wants to support concurrency. Seems a lot easier to reason about. See go or haskell for example.
- inglor 11y agoYou know, Haskell's IO is pretty much equivalent to JavaScript's promises. JavaScript's generators let you have do notation in JavaScript, and using async/await the "evented" stuff becomes not so evented and pretty easy to reason about. 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.
- inglor 11y agoSo much wrong in one place. A promise is the IO monad, with `then` being `>>=` [1]. 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 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).
- asQuirreL 11y agoNot sure promises are equivalent to the IO monad in particular. They could form a Monad instance, although that is not the interface they have chosen to expose. It does seem it would be more similar to the `Either` monad, however.
- inglor 11y agoThe type signature, with `catch` is something like Either mixed with `IO`, it's just a specific form of continuation[1]. Promises are not _exactly_ like an IO monad because it would not be pragmatic, but it serves the same purpose (controlled side effects and boxing temporal state) in the same way (a bind operator). 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 http://blog.sigfpe.com/2008/12/mother-of-all-monads.html [2] : for example http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html http://adit.io/posts/2013-04-17-functors,_applicatives,_and_...
- wildpeaks 11y agoI can't wait for async/await native in Node because they're imho required for really unlocking its potential; sticking only to es6 promises and generators feels incomplete. Edit: I mean ES7 async, not async.js (even though it's a great library)
- k__ 11y agoI use promises most of the time. In frameworks like koa they even got a bit nicer. 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.
- inglor 11y agoFor this there are Observables and async iterators. I warmly recommend https://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2014/Keynote-Duality https://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2014/Ke... . 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 https://github.com/zenparsing/es-observable and https://github.com/Reactive-Extensions/RxJS https://github.com/Reactive-Extensions/RxJS
- greggman 11y agoSince we're talking about promises ... can anyone point to some good patterns for nested promises and not losing errors to the either? 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.
- inglor 11y agoHey! In NodeJS we added a handler that helps you with that here: https://nodejs.org/api/process.html#process_event_unhandledrejection https://nodejs.org/api/process.html#process_event_unhandledr... Here is a talk I gave about adding it last June: https://www.youtube.com/watch?v=LGpmUyFnyuQ 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.
- Too 11y agoChromes "break on exception"-option also breaks on unhandled promise reject().
- berryg 11y agoTake a look at elm-lang.org. It is a functional language that compiles to javascript. Effects are implemented as Tasks (as I understand kind of like a Monad). It has very good interoperability with javascript code.
- dangoor 11y agoYeah, Richard Feldman's Strange Loop talk[1] touched upon Tasks and they do indeed look exactly like what I'm looking for. Elm does look very nice. Not sure if I'd get the team on board with that kind of change ;) [1]: https://www.youtube.com/watch?v=FV0DXNB94NE https://www.youtube.com/watch?v=FV0DXNB94NE