5 ms·
Core.async is not a substitute for Rx. As a disclaimer I'm the author of an Rx-inspired library for Scala [1] and that also works for Scala.js in the browser.
by bad_user 11y ago
Core.async is not a substitute for Rx.
As a disclaimer I'm the author of an Rx-inspired library for Scala [1] and that also works for Scala.js in the browser. Shameless plug aside, Scala also has Future/Promise in its standard library and now due to macros support it got scala/async [2], a library that gives you the "await" keyword in Scala, so in Scala you also get this kind of M:N multithreading that looks like synchronous code. This in addition to Akka and other possibilities.
In other words I've worked with both approaches and Core.async is not comparable with Rx. I do understand the author's woes, as sometimes the Rx model is misapplied, plus it's hard to understand for the unfamiliar.
One of my colleagues was complaining once that "but I don't know what the debounce operator does and it's hard for me to read that". And I told him: yeah dude, but try implementing the logic in debounce by yourself and see how readable that is.
And that's exactly why Rx is problematic. On one hand because stream processing is fundamentally hard, no matter what model you choose. And on the other hand Rx comes with a lot of useful operators that do a lot for you, but then you have to learn about them.
For the naysayers, I'll just leave this piece of code with a challenge for implementing it with core.async and compare in terms of readability and note this is a copy paste from actual production code ...
commands
.groupBy(w => (w.assetID, w.commandID))
.mergeMap { gr =>
gr.timeout(30.seconds, Observable.empty)
.throttleLast(1.second)
.distinctUntilChanged
.echoRepeated(5.seconds)
.whileBusyBuffer(DropOld(30))
}
What it does is to split the signals for each asset and command, for each of these it's supposed to sample the signal by 1 second, but in case the same value is repeated over and over again or in case the channel goes silent, then the last value will end up signaled every 5 seconds (reducing the traffic to our OpenTSDB). Finally for each key we close the stream after 30 seconds of inactivity. And then for each such key it does buffering of at most 30 elements and in case the consumers are too slow, then these buffers start dropping older elements on overflow. And then we merge everything back.
I would also show you how we are modeling state machines with the "scan" operator, state machines that are evolved from signals coming from multiple sources, but the sample would be too long. In any case "scan" allows you to use pure functions and data-structures, so you can test your business logic without interactions to third party services, mocks, stubs or whatever.
I have to deal with such code all the time. And I've seen such code implemented in a classic fashion as well. You basically end up with Maps storing stuff and with ifs and whiles and with manual timers in an unholy dance of mutation so hard to understand and debug that it would make grown men cry.
But then such solutions are not silver bullets. Rx, CSP, futures, actors are not silver bullets to be applied everywhere, with all of them having a sweet spot for which they excel. I'm actually using Rx, actors, futures, scala/sync in the same project and it's great.
Also, one last note: Rx is not FRP ;-)
[1] https://github.com/alexandru/monifu/ https://github.com/alexandru/monifu/
[2] https://github.com/scala/async https://github.com/scala/async
- tunesmith 11y agoAs soon as OP started talking about Go and Clojure and Core.async, I wondered if Scala.js would give him the same sort of benefits in this case as ClojureScript. But I don't know a lot about Scala.js yet and if you can actually run an actor system on the javascript frontend.
- bad_user 11y agoYou can run an actor system in Javascript of course and there are partial ports of Akka available, but are not meant for production use. I wouldn't use Akka in the browser though, as it's too heavy and I feel that the kind of tasks meant for Akka do not happen in the browser, though for Node.js that would be another story.
- divs1210 11y agoI'm not a core.async/UI wizard but have a look at this [0]. It's a tutorial for building a reactive ToDo List application using core.async for event processing, crate [1] for rendering and jayq [2] for DOM manipulation and ajax calls. Interesting, though I use re-frame [3]. [0] http://rigsomelight.com/2013/07/18/clojurescript-core-async-todos.html http://rigsomelight.com/2013/07/18/clojurescript-core-async-... [1] https://github.com/ibdknox/crate https://github.com/ibdknox/crate [2] https://github.com/ibdknox/jayq https://github.com/ibdknox/jayq [3] https://github.com/Day8/re-frame https://github.com/Day8/re-frame
- bonobo3000 11y agoif you don't mind me asking, how do you really learn about the different models of concurrency/parallelism well enough to be able to compare them based not only on API/programming model but also performance and low-level differences? as an example,i want to build a web crawler. ive worked with akka actors, and that seems like a good fit because the messaging logic for scraping is simple and it gives me remote distribution for free.. but then i see all these other models and wonder - what is the difference in doing it with Rx or futures etc? is there any difference besides choice of programming model in terms of how these things actually map to low level primitives?
- dkersten 11y ago