This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-04-14
Channels
- # beginners (53)
- # boot (93)
- # cider (13)
- # cljs-dev (17)
- # cljsrn (20)
- # clojars (1)
- # clojure (349)
- # clojure-austin (1)
- # clojure-gamedev (5)
- # clojure-italy (1)
- # clojure-nl (16)
- # clojure-poland (1)
- # clojure-russia (26)
- # clojure-spec (57)
- # clojure-uk (6)
- # clojurebridge (5)
- # clojurescript (145)
- # code-reviews (2)
- # core-async (88)
- # cursive (1)
- # datomic (3)
- # defnpodcast (10)
- # events (7)
- # hoplon (20)
- # instaparse (1)
- # jobs-discuss (15)
- # keechma (26)
- # lein-figwheel (2)
- # leiningen (1)
- # liberator (11)
- # lumo (40)
- # off-topic (54)
- # om (32)
- # onyx (11)
- # pedestal (6)
- # perun (4)
- # planck (6)
- # re-frame (4)
- # reagent (12)
- # ring (3)
- # ring-swagger (10)
- # rum (1)
- # testing (4)
- # timbre (1)
- # unrepl (20)
- # untangled (111)
- # vim (1)
How can I create a channel with no buffer?
I tried
(def c (chan))
(put! c "hello")
(go
(println "c: " (<! c)))
In this case, the channel should be empty, when the reader reads it
But in reality, it prints c: hello
Here is a klipse snippet that illustrates this: http://app.klipse.tech/?eval_only=1&cljs_in.gist=viebel/7bc06c02d0433a0f00b214a3d3aa1443
What I want is to create a channel such that messages that are written while no reader reads the channel are dropped
who can help?
put! actually buffers too
and you can use size 0, but then you have to use >! and other blocking/parking methods to put values in the chan
put! has to use a buffer since it’s guaranteed to immediately return, even if the chan is full
@joost-diepenmaat It doesn't work for me with a buffer size of 0 neither with dropping-buffer
nor with sliding-buffer
@viebel What you can do is something like:
(def c (chan))
(alts!! [[c "hello"]] :default false)
That will immediately return if there are no pending takes on c
, otherwise put "hello"
into c
In the former case it will return [false :default]
In the latter [true c]
Thanks @dergutemoritz. That works fine
Do you have any idea why it cannot be done in the straightforward way - using put!
?
(In cljs, there is no alts!!
, so I have to use alts!
- which must be inside a go
block 😞
Because there is no buffer available with that semantic
I just thought of another way, though, that should work with put!
oh. what is it?
If you put a mult
in between it should work
But then you have to tap and untap on the reading side everytime ... not ideal either I guess
Not ideal
Well you can hide the (go (alts! ...))
behind a function, of course 🙂
Would it make sense to create a buffer policy where there is no buffer but puts
will never be blocked?
Sure, you could roll your own buffer with those semantics
But that's a bit trickier
I don’t understand why this is not the semantics of (chan)
?
It should create a channel with no buffer!!!!
Why (alts! [[c "hello"]] :default false)
behaves differently than (put! c)
?
in the case of no pending takes
To me it’s really confusing!!
(chan) does create a channel with no buffer
the problem is that put! never blocks and uses an internal buffer when the chan’s buffer is full or doesn’t exist
so don’t use put!
then the other problem is that the semantics of a chan without a buffer is that it parks/blocks until there is a pending take
and you cannot create a buffer with size 0 (I think) that would convert it to something like “dropping”
basically because that would mean you’d pretty much always would be dropping messages
unless you manage to have more than one pending take on the chan at all times
I’m not sure that a dropping buffer with size 0 makes sense but I may be just confused
My use case is something like this: i want to send a :stop
message on a command channel but the :stop
should be executed only if an active process is listening to the channel
If the message is buffered when no active process is listening to the channel, then when a process will connect to the channel (after a while) it will read the :stop
message that was sent before
This is why I thought about having a channel with no buffer
from the doc of put! it’s not very clear that the messages are buffered even if the channel has no buffer
It seems that @dergutemoritz ’s suggestion with alts!!
or alts!
is the best solution (actually the only one!)
@viebel Is there only ever going to be at most a single active process or can there be more than one at the same time that should then all react to such a :stop
message?
never more than one!
OK then. Otherwise you'd have to use the mult
approach
Yes I know
:thumbsup:
Could you elaborate @dergutemoritz about how will I solve my no-buffer issue with mult
?
I tried
(def c (chan))
(def mult-c (mult c))
(def cx (chan))
(tap mult-c cx)
(>!! c "hello")
(<!! cx)
Yep, that should do the trick
(<!! cx)
returns “hello”
While no channel is tapped to the mult, all messages will be dropped
Right, because it's tapped
So while your process is active, it should be tapped
And when it's done, it should untap itself
Oh I see
(def c (chan))
(def mult-c (mult c))
(def cx (chan))
(put! c "hello")
(tap mult-c cx)
(go (println "read: " (<! cx)))
(untap mult-c cx)
This work exactly as I want
nothing is read!
By the way, I discovered something interesting
(def c (chan))
(def mult-c (mult c))
(put! c "hello")
(go (println "read from c: " (<! c)))
If the channel is multiplied, then put!
doesn’t buffer
even without tapping into another channel!
Yeah, that's how mult
is supposed to behave
i.e. don't buffer messages when there are no taps
Same is true for pub
btw because it's built on top of mult
But then I cannot read from the original channel at all!!!
(def c (chan))
(def mult-c (mult c))
(go (println "read from c: " (<! c)))
(go (>! c "hello"))
nothin is printed!
Oh right, sorry, I didn't read that closely enough
Yeah, the input port of a mult
is kind of bound to it
You always have to go through tap
if you want to read from it
OK. Thanks!
The docs are not very explicit about it but it's the only way it can work if you think about it
otherwise one reader from the original channel will be able to “steal” the messages from the multiplied channel
Yeah, it would result in pretty unpredictable behavior
That makes sense
In fact, maybe you can even do that
But that would be pretty confusing 😄