So in the core-async videos, the example shows the consumer calling
close! to signal to the collection of assembly workers that they should stop producing cars.
In this respect,
close! seems to work like a kind of super-fast back-pressure. Whereas backpressure says “woah that’s too fast”,
close! says “that’s enough!”. It has the advantage of being final and acting instantly, in that you don’t need to wait for the buffer to fill before the effect is visible to the producer.
But then yesterday I got into a conversation on the Clojurians Slack that seemed to suggest this was the wrong way to think about. This Google Groups post by Brandon Bloom goes into more detail, and I followed up with him later. But the essential argument is that a channel should be an abstraction for one-way communication, from producer to consumer. As such, only the producer should ever close the channel. I believe that the Go language may enforce this restriction with the type system. On this view, closing a channel should semantically correspond to “nothing more to send, ever”, rather than a way for the consumer to say “no more, please”.
On this view, if you have a process that’s filling a channel with a potentially infinite stream of values (say by polling an external source), and you want to close the channel, then you should create a second, separate means of communication to tell the producer to close the channel. What Brandon recommended was creating a second channel,
stop-chan, whose only purpose is for the consumer of the first channel to be able to signal to the producer of the first channel to close it. You send that message by closing stop-chan; you don’t even need to put a value in it.
This was a new pattern to me. I’m wondering if it’s typical of how people use core.async? Or of how they should use it? Or is it a golang-ism which is inconsistent with other aspects of core.async’s and clojure’s approach?