Fork me on GitHub
#core-async
<
2017-03-14
>
lwhorton17:03:34

Heya guys, I was hoping someone might be able to answer a question on core.async related to nested takes?

Alex Miller (Clojure team)17:03:13

usually it’s best to just ask a question rather than ask to ask… go for it!

lwhorton17:03:39

I think this is the minimal case:

(go-loop []
         (let [foo (<! in)]
           (let [t (timeout 1)
                 [v c] (alts! [in t])]

             )
           )
         )

lwhorton17:03:30

does that foo-take only get invoked once per loop, or will I get some strange behavior doing this… such that the alts! and the foo take are competing to take off of chan in?

Alex Miller (Clojure team)18:03:35

a go loop can only park at one spot so shouldn’t be any competition

lwhorton18:03:15

for example, my intent is to essentially check a condition, then put the take back into the channel if I don’t like it:

(go-loop []
 (let [foo (<! in)]
   (let [t (timeout 1)
         [v c] (alts! [in t])]
     (if some-condition
       (do ..)
       (do 
         (>! in v)
         (recur))))))

Alex Miller (Clojure team)18:03:09

well it’s a queue, so that changes the ordering

lwhorton18:03:00

ah, didn’t think about that. in my particular case it shouldn’t matter… it just felt iffy nesting takes on the same channel like this ^

Alex Miller (Clojure team)18:03:21

you might look at pub/sub if you want to only see a subset of things that match a condition. although I guess it doesn’t look condition depends on v in your case

hiredman18:03:23

having a process (a go loop or a thread) that reads and writes to the same channel is an easy way to introduce bugs, I would recommend implementing that condition checking as either a filter xform on a channel, or a process that reads from one channel and only passes data on to another channel if it passes the condition

Alex Miller (Clojure team)18:03:28

it was unclear to me if the condition is related to the values on the channel or is external

lwhorton18:03:28

just in case you’re curious, the purpose is 1) learn async 2) try to get something more easily testable than js/setTimeout and atoms (cljs)… and the problem at hand is “if a disconnect occurs, notify the user, but only if we don’t reconnect within X seconds”, and the trickery is there’s no ordering guarantees to connect/disconnect… they could come in any order, any number of times

lwhorton18:03:02

so the thought was pull from the incoming messages in (chan), and depending on the message notify a reconnect (but only if we know we are actually disconnected) or setup a timeout where after X seconds (if no more new messages arrive) notify the user of the disconnect

lwhorton18:03:02

“do foo after X timeout, but only if nothing else happens” seems like an appropriate case for core.async

noisesmith18:03:24

lwhorton: if your in doesn’t have a buffer, that code is very likely to lock up (depending on what else is using in of course). I find that core.async works better when a go block doesn’t output to the same channel it reads from. feedback has complex and unpredictable consequences, if you aren’t using it as an adaptive signal flow modulation technique, it’s likely to do things you don’t anticipate or want.

noisesmith18:03:06

(feedback being a signal that reaches back as an input to the same process that produced the signal)

noisesmith18:03:04

like - it almost looks like you are doing negative feedback here, but I’m not so sure...

lwhorton18:03:30

that’s a good observation on all counts @noisesmith @alexmiller @hiredman thanks for your thoughts