
Communicating Sequential Processes - swannodette
http://swannodette.github.io/2013/07/12/communicating-sequential-processes/
======
alco
This looks nice. Less readable than Go (is there GoScript yet?), but still
fairly straightforward.

One remark I'd like to make is that I don't see this as having a big advantage
over FRP.

The examples with mouse coordinates look like an imperative approach to FRP.
With the latter, one wouldn't have to explicitly set up a channel and read
from it -- that is an implementation detail in FRP.

To emphasize the contrast, I'd call this channel-based approach an Imperative
Communicating Programming (ICP). Your code does not react to changes like it
does with FRP. Instead, you as a programmer ask for changes, very often in an
infinite loop, and then transform those changes into a side-effect in the
browser.

On one hand, channels + goroutines provide a single abstraction with which it
is kind of straightforward to implement various concurrently executing threads
of code. On the other hand, those infinite loops and their proliferation in
the channel-based code will definitely cause some people to cringe and go with
FRP instead.

I don't think FRP is as applicable as channels to as many use cases. Channels
are more low level and therefore more potent. But for what FRP does, it
provides a better (read "more concise", or "declarative") abstraction for it.

~~~
swannodette
Note that in some ways core.async is a bit more flexible than Go - for example
you can dynamically select over a changing list of channels. I've found this
to be really handy especially when you're receiving channels on channels.

you can do everything in an FRP style if you like with core.async, it's
flexible enough for that. But I think for less toy examples this is
undesirable as you allude.

~~~
mseepgood
> Note that in some ways core.async is a bit more flexible than Go - for
> example you can dynamically select over a changing list of channels

[http://golang.org/pkg/reflect/#Select](http://golang.org/pkg/reflect/#Select)

~~~
swannodette
You should look a bit more closely at what I said :)

EDIT: Oops, I didn't see you had linked to the _reflect_ features. I did not
know that and that is very cool.

~~~
mseepgood
You said: "for example you can dynamically select over a changing list of
channels"

reflect.Select does exactly that.

------
airlocksoftware
Cool stuff! A couple of days ago I listened to Rich Hickey talk more about
core.async on the most recent ThinkRelevance podcast:

[http://thinkrelevance.com/blog/2013/07/10/rich-hickey-and-
co...](http://thinkrelevance.com/blog/2013/07/10/rich-hickey-and-core-async-
podcast-episode-035)

I've written a few client side projects in ClojureScript, and I haven't been
totally happy with the way I end up doing event handling. I'm excited to give
this a try.

By the way, I love that this is the sort of thing you can do with just a
_library_ in Clojure.

~~~
dominotw
Brilliant!!. Can someone point me to an open source project which uses
core.async so I can see it in action.

~~~
juliangamble
This is an example of Peter Norvig's spellchecker written with core.async by
Stuart Sierra (@stuartsierra):
[https://gist.github.com/stuartsierra/5954022](https://gist.github.com/stuartsierra/5954022)

This is an example of Rock Paper Scissors by Alex Miller (@puredanger):
[http://tech.puredanger.com/2013/07/10/rps-core-
async/](http://tech.puredanger.com/2013/07/10/rps-core-async/)

------
saljam
Brilliant! I had always hoped CoffeeScript or somehow a JS library would add
blocking channels like this. Writing JavaScript is a pain after being spoilt
by Go.

I'm quite curious about what the compiled code looks like. (On a mobile now,
I'll have a look when I can.)

~~~
amasad
It seems like the compiled js code from the page's examples is quite large:
csp.js minified ~83kb

I wonder if most of that is the runtime and libraries or the resulting
JavaScript code is just that big.

~~~
swannodette
There is no runtime and note that's 22k gzipped. This is far smaller than
jQuery + Underscore.js + persistent data structure library + stream
implementation + async control flow library gzipped which is what you're
getting. _jQuery alone is 33k gzipped_.

------
alco
One thing that is not covered in the post is how should we clean up those
goroutines that are blocked on channels. I'm not familiar with internal
workings of core.async, so I'm looking at it from Go's point of view.

Imagine that in the search example, inside the `google` function, we want to
read from 100 channels. And each call to `fastest` is supplied with 100
arguments. If on average we get 100 results back in the allotted time, 900
goroutines will be left in a blocked state waiting for someone to read from
their respective channel.

I'm guessing those goroutines are cheap and are implemented as some sort of
state machine that maps to callbacks. But all those blocked goroutines should
still incur runtime cost. Will the GC kick in collect those?

If this issue is really there (i.e. if I'm not mistaken), imagine what will
become of your one-page-web-app after you click on that Search button a dozen
of times.

~~~
swannodette
go blocks are cheap to construct and yes they will be GCed. You can trivially
debounce the click channel.

~~~
alco
Thanks for the info! I'm willing to get my hands dirty and see how it's all
implemented there.

Just for the record, in Go, if you leave a goroutine blocked on a channel, the
channel and the goroutine will remain on the heap unless you read everything
from the channel (normal way) or close it (and get a runtime panic).

------
ganarajpr
Can some of the clojure and clojurescript gurus take some time to write
beginner friendly, hand holding tutorials? I mean, I can see the power of
these technologies but the very thought of climbing a learning curve AS WELL
AS a getting started curve ( that too without any external help! ) is the
single most important thing that turns people off.. especially me. My general
complaint is with regard to how many tutorials and even books are out there on
these topics! Countable, with the fingers in one hand perhaps!

~~~
calibraxis
Discoverability is a problem, but the Clojurewerkz people are top-notch
([http://clojurewerkz.org/](http://clojurewerkz.org/)). These are helpful:

* Intro: [http://clojure-doc.org/](http://clojure-doc.org/)

* Libs: [http://www.clojure-toolbox.com/](http://www.clojure-toolbox.com/)

* Examples: [http://clojuredocs.org/quickref/Clojure%20Core](http://clojuredocs.org/quickref/Clojure%20Core)

* Pedestal: [https://github.com/pedestal/app-tutorial](https://github.com/pedestal/app-tutorial)

Also a few books at different levels:

* [http://www.clojurebook.com/](http://www.clojurebook.com/)

* [https://leanpub.com/fp-oo](https://leanpub.com/fp-oo)

* (2nd ed early access available) [http://joyofclojure.com/](http://joyofclojure.com/)

* [http://pragprog.com/book/shcloj2/programming-clojure](http://pragprog.com/book/shcloj2/programming-clojure)

* [http://www.manning.com/rathore2/](http://www.manning.com/rathore2/)

* [http://www.packtpub.com/clojure-data-analysis-cookbook/book](http://www.packtpub.com/clojure-data-analysis-cookbook/book)

~~~
alexott
I would also mention following tutorial on CLJS:
[https://github.com/magomimmo/modern-
cljs](https://github.com/magomimmo/modern-cljs)

------
mseepgood
"languages like CoffeeScript, Dart, and TypeScript. These languages fail to
address the single largest source of incidental complexity for any sizeable
client side application - concurrency."

Dart fails to address concurrency? I don't think so:
[http://www.dartlang.org/docs/dart-up-and-
running/contents/ch...](http://www.dartlang.org/docs/dart-up-and-
running/contents/ch03.html#ch03-dartisolate---concurrency-with-isolates)

~~~
swannodette
I'm not sure you actually read the post, isolates do not address the same
issues at all - you can't share data between isolates and you can't put
isolates onto isolates limiting coordination possibilities - all of these are
possible with channels.

~~~
mseepgood
You can at least send a SendPort over a SendPort:

"Isolates send messages using SendPorts, and receive them using ReceivePorts.
The content of a message can be any of the following:

* (...)

* An instance of SendPort"

You can prefer one or the other model, but saying that Dart fails to address
concurrency is just not true.

~~~
swannodette
I think you're taking my use of the word out of context of the whole post. I'm
talking about the concurrency that is imposed by the very nature of client
side programming - you have no choice. Isolates don't allow to you coordinate
the concurrency that is _already present_.

------
vanderZwan
Does anyone have any idea why the mouse-over examples are a more CPU intensive
task for Firefox? On my laptop, moving the mouse a lot results in 15% CPU
usage, and if I jitter it fast enough it maxes out at 22%. That won't lock up
the browser if I'm not doing anything else but still feels like it will drain
the laptop battery notably faster with intensive use, if you catch my drift.

With Chrome I can't get it above 4%. IE 10 is somewhere in the middle with 10%
(and also has a bug when resizing the window, giving Y values like
2236.65990234375, with the fraction part being constant).

EDIT: Both Opera 12 and Opera 15: 6 to 8%

Also, the second/third examples seem a bit laggy with all browsers: if I shake
the mouse quickly the numbers keep updating for a while after I stop. I guess
that this is because instead of showing the most recent value it shows all the
location values, but the screen updates are slower than the mouse updates?

Either way, when the mouse stops moving while the numbers still update,
Firefox only takes 6% of the CPU. Not sure if that clarifies anything, but it
might help identify the cause.

~~~
swannodette
I don't think you can come to any conclusions from these numbers. I see the
exact same CPU utilization across browsers if I replicate the styles and write
this JavaScript instead:

    
    
       var loc = document.getElementById("location");
    
       window.addEventListener("mousemove", function(e) {
         loc.innerHTML = e.pageX + ", " + e.pageY;
       });
    

Which is saying something, the ClojureScript is doing a lot more work and it
ain't slow ;)

I suspect all the cost is from repainting large areas at the speed of mouse
movement. But the mouse examples are for illustration - in production code
you'll probably want to throttle (which would avoid piling up the repaints you
observed on slower machines) as well as address the IE 10 edge case.

~~~
vanderZwan
Well, my question was why one browser was slower than the other - I didn't
expect ClojureScript to be the cause of the problem. I was just curious about
what might cause the difference.

> I suspect all the cost is from repainting large areas at the speed of mouse
> movement.

I'm not really a web dev, but isn't this a reflow, not a repaint? Could that
be the reason for the difference in performance too? What happens if you use
canvas instead of changing a div?

BTW, I forgot to mention this in the previous comment, but: this is pretty
cool! I echo the "being spoilt by Go" sentiments of others, so I'm happy to
see this library.

------
rdtsc
Maybe it is just me, but I prefer logically to think of actors (or processes)
as concurrency primitives not channels, kind of like what Erlang has. For
example in go the primary question is "what channel to I write or read from?",
in Erlang it is "what is the pid of the process, so I can send it a message?".

~~~
aufreak3
Channels are a neat generalization of what Erlang has. Btw the first example
used in the post isn't all that "fall out of your chair". Here is the same
implemented in pure JS using my toy IO.js library -
[https://gist.github.com/srikumarks/5992336](https://gist.github.com/srikumarks/5992336)

~~~
swannodette
People keep focusing on the first example. If you're going to compare, I think
it's much more illuminating to see versions of the final example.

~~~
aufreak3
Challenge accepted.

[https://gist.github.com/srikumarks/5992608](https://gist.github.com/srikumarks/5992608)

~~~
swannodette
Thanks!

------
VMG
Very cool - I didn't realize that core.async has made it into ClojureScript.
Seems more like a viable language for web programming every day.

~~~
Sukotto
In your opinion, what is missing that it needs to become viable?

~~~
VMG
The last time I tried it I didn't find a broadly accepted server-side
framework that automatically compiles ClojureScript assets, but I haven't
looked in a while.

~~~
cgag
Why wouldn't you just deploy the compiled js as a static asset? If you want to
autocompile it while developing, leiningen + cljs-autobuild handle that well.

~~~
VMG
I was looking for some server-side framework for also handing HTTP requests
and REST calls

~~~
puredanger
You might want to take a look at Liberator [http://clojure-
liberator.github.io/liberator/](http://clojure-liberator.github.io/liberator/)

------
brucehauman
Great post!

And here's a todo's example that I wrote [https://github.com/bhauman/async-
explore/blob/master/src/tod...](https://github.com/bhauman/async-
explore/blob/master/src/todos_first/core.cljs)

------
realrocker
Why do you call alts! input choices as non deterministic ?

~~~
sgrove
You won't know _which_ channel is going to give you a value ahead of time, it
depends on runtime conditions.

But really, you don't care if the user pushes the keyboard or moves the mouse
first, you just want to handle each event as it happens in essentially a
sequential manner.

~~~
realrocker
If I am forcing it to be sequential, aren't the choices now determinitic?

~~~
brandonbloom
The default for multiplexing is non-deterministic choice. You can specify the
:priority flag [1] if you want deterministic choice when multiplexing. Reads
and writes will block for a non-deterministic amount of time, but their
sequencing will be deterministic. That's the beauty of the CSP model: You can
achieve some level of local determinism within a particular thread of control.
Makes it much easier to reason about the non-deterministic outside world.

[1]:
[https://github.com/clojure/core.async/blob/bb77337b3e9ce2118...](https://github.com/clojure/core.async/blob/bb77337b3e9ce2118916fe84ae37c064a2eb9c55/src/main/clojure/clojure/core/async.clj#L229)

~~~
realrocker
makes sense , thank you!

------
MaysonL
Obligatory Hoare link:
[http://usingcsp.com/cspbook.pdf](http://usingcsp.com/cspbook.pdf)

------
novaleaf
the article is a bit of a cheap shot against Typescript. They have had async
in the roadmap the last 6 months at least (and the public project is only
about 10 months old).

IIRC, async is the next big feature on the roadmap, and going to be in before
v1.0 (v0.9, released 2 months ago, added generics)

given the pace of development, typescript v1 should be done in 6 months or
less.

~~~
chongli
I don't see how that makes it a cheap shot. Everyone is drawing from the same
pool of ideas that were discovered decades ago. Could you be more specific?

~~~
novaleaf
typescript is very popular for how young it is. so given that the thing is
still a very young, alpha product, saying that they are neglecting feature X
is a bit too much. better to just not even mention it.

~~~
chongli
Yeah, the rhetoric at the beginning is a bunch of cheap shots at different
languages. Having said that, it is clearly separated from the rest of the post
by the line: _Enough rhetoric, let 's see how core.async works in practice._

As for language features? core.async is not a feature of
Clojure/ClojureScript; it's merely a library.

------
bascule
If you're interested in this sort of thing, also take a look at MenTaLguY's
WebActors:

[https://github.com/mental/webactors](https://github.com/mental/webactors)

~~~
swannodette
Yeah I've seen this before though it doesn't really allow you to share
arbitrary data as it relies on Web Workers (if you share data with a worker it
will disappear from the sending process). I'd also be concerned about the
performance of the implementation, core.async adopts C#'s approach which is
pretty light weight.

------
mrcactu5
Where does the blog style come from ?

~~~
brucehauman
I'm pretty sure it's standard jekyll
[http://jekyllrb.com/](http://jekyllrb.com/)

