Skip to content

Instantly share code, notes, and snippets.

@StevenACoffman
Last active March 2, 2017 00:20
Show Gist options
  • Save StevenACoffman/5ed1b5e896938d973dbd08ca75e850e1 to your computer and use it in GitHub Desktop.
Save StevenACoffman/5ed1b5e896938d973dbd08ca75e850e1 to your computer and use it in GitHub Desktop.
Erik Meier Four Fundamental Effects

Erik Meier -- The Four Fundamental Effects

One Many
Sync T Enumerable[T]
Async Future[T] Observable[T]
  • future = promise
  • observable = rxjs/baconjs/cyclejs/kefirjs observable

"core.async = FRP + coordination language" -- David Nolan

Bret Young [says here]:

In Clojure Core Async Channels Rich Hickey writes about the rationale for core.async. He says, "Events complect communication and flow of control. While there are various mechanisms to make events/callbacks cleaner (FRP, Rx/Observables) they don't change their fundamental nature, which is that upon an event an arbitrary amount of other code is run, possibly on the same thread, leading to admonitions such as 'don't do too much work in your handler', and phrases like 'callback hell'."

I believe the fundamental complaint with the FRP, etc. approach from David Nolan and Rich Hickey is expressed in the phrase "Events complect communication and flow of control." In FRP style approaches you are tying the event stream directly to the code that is executed when events happen on the stream. With the channel abstraction you have separated communication (something is put or taken from the channel) from flow of control (arbitrary code executed as a result of item taken off the channel. And, more importantly, the consumer and producer on either end of the channel change as desired (it not fixed, like a handler is, at stream definition time). Plus, channels are really first class in that a channel can be put on another channel.

So, I think I now grok what is meant in the discussions when the claim is made that FRP, etc, lacks coordination. If I've missed something or you have something to add, let me know.

From Guillermo Winkler on stackoverflow: I think main problem is your assumption about the tackled problem are not quite so, since none of them are tackling the asynchronicity "problem".

The abstractions

FRP main idea is propagation of change, think about accomplishing the same thing Excel does, where you define cells depending on each other in a cascade, and when one cell changes, all the dependent cells on the cascade are recalculated.

core.async main idea is systems decomposition, think as separating concerns using a queue in the middle of different processes, in core.async case instead of queues you have channels but you get the idea.

So, removing the pyramidal code is not the objective of either technology, and they operate on different abstraction layers.

About complecting control flow

The idea about complecting communication and flow control is taken from the original core async post.

While there are various mechanisms to make events/callbacks cleaner (FRP, Rx/Observables) they don't change their fundamental nature, which is that upon an event an arbitrary amount of other code is run, possibly on the same thread, leading to admonitions such as "don't do too much work in your handler", and phrases like "callback hell".

Rephrasing, if you have business domain code inside an event handler, you have complected the X event processing with the what to do when X happens.

Which is what core.async tackles, since introducing a queue/channel in the middle, helps for a better separation of concerns.

Implementation

All your questions regarding callbacks and passing observable endpoints as parameters are just implementation questions, it really depends on the Rx implementation and API.

If you look at React reusable components you really don't have much of a callback hell to be seen, and you get that idea of passing observables around.

Final thoughts

Even if Rx can be used to model any data flow, is more commonly used for UI Rendering a-la Excel, to simplify how you update your view when your model changes.

On the other hand, Core.Async can be used to model separation of concerns when any two sub-systems communicate with each other (same usage scenario as queues), using it on the UI rendering chain main idea is to separate:

  • Server side event generation and processing
  • How that event affects your model

So you can have core.async and FRP together, since core.async will separate concerns, and FRP will define your cascading data-flow once your model is updated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment