Fork me on GitHub
#core-async
<
2021-12-15
>
drewverlee15:12:51

Given the code below, expected to see the my repl to output the "1" instead nothing happened. Can someone explain why. I created two channels, the go loop created a running loop where the value should be taken from in-ch and put on out-ch if odd, then the take! should take from out-ch and call println on the value in the callback.

(def in-ch (chan))

  (def out-ch (chan))

  (go-loop []
    (let [val (<! in-ch)]
      (when (odd? val)
        (>! out-ch val)))
    (recur))

  (put! in-ch 1)

  (take! out-ch println)

dpsutton15:12:45

works for me:

% clj -A:async
Clojure 1.10.3
user=> (require '[clojure.core.async :refer [chan <! >! put! take! go-loop]])
nil
user=> (def in-ch (chan))

#'user/in-ch
user=> user=>   (def out-ch (chan))
#'user/out-ch
user=>
user=>   (go-loop []
    (let [val (<! in-ch)]
      (when (odd? val)
        (>! out-ch val)))
    (recur))
#object[clojure.core.async.impl.channels.ManyToManyChannel 0x605c2b9f "[email protected]"]
user=>
[email protected] async % clj -A:async
Clojure 1.10.3
user=> (require '[clojure.core.async :refer [chan <! >! put! take! go-loop]])
nil
user=> (def in-ch (chan))
#'user/in-ch
user=> (def out-ch (chan))
#'user/out-ch
user=> (go-loop []
    (let [val (<! in-ch)]
      (when (odd? val)
        (>! out-ch val)))
    (recur))
#object[clojure.core.async.impl.channels.ManyToManyChannel 0x1adc38a0 "[email protected]"]
user=> (put! in-ch 1)
true
user=> (take! out-ch println)
1
nil
user=>

drewverlee15:12:07

does it matter that i'm in cljs?

drewverlee15:12:28

err it is working

dpsutton15:12:49

oh that’s good

drewverlee15:12:01

emacs did a thing with my repl that is confusing to me. The value are above my user> and cljs.user> prompt!

drewverlee15:12:35

I had to scroll up

drewverlee15:12:52

ignore the "val: 1" outputs, i added that print statment

drewverlee15:12:59

anyway, thanks.

dpsutton16:12:53

no problem. this is an nrepl problem i think. nrepl works great for expressions returning values. It’s not so great for arbitrary printing that happens asynchronously

drewverlee16:12:58

is there a better way to track things?

dpsutton16:12:55

track what?

drewverlee16:12:00

asynchronous events i suppose. I was just surprised by the behavior and it lead me to believe people weren't doing this, when most tutorials i see on async do involve repl output. But maybe there is some sort of way to check the system that isn't staring at the docs. I suppose specs, graphs, etc could be used.

noisesmith20:12:57

treating (atom []) as a log of events, with (swap! a conj x) replacing (println x) is a start

👍 1
noisesmith20:12:38

println for async debugging has multiple problems, but most repls don't move the prompt around obscuring the timing like emacs does

👍 1
drewverlee16:12:24

Given the following code (same as above + 3 lines marked with X) i expected my repl to just ouput 9 because i closed the go-loop channel. Instead i get the

9
11
(def in-ch (chan))

  (def out-ch (chan))

  (def looper
    (go-loop []
      (let [val (<! in-ch)]
        (when (odd? val)
          (>! out-ch val)))
      (recur)))

  (put! in-ch 9)

  (take! out-ch println)

 X (close! looper)

 X (put! in-ch 11)

 X (take! out-ch println)
Did i not close the channel, or does putting a value on a chan re-open it? How do modify a running go-block at run time or is that not possible? How do you do it in repl development at least.

Alex Miller (Clojure team)16:12:34

close! looper closes the output channel of the go-loop, it doesn't stop the loop

Alex Miller (Clojure team)16:12:58

usually, you want to put an if at the beginning of your go-loop that will stop when receiving nil (protip: if-some is useful here) and then you can close the in-ch to stop the loop

drewverlee16:12:46

like this?

(def looper
    (go-loop []
      (if-some [val (<! in-ch)]
        (do
          (>! out-ch val)
          (recur))
        (close! in-ch))))

Andrew16:12:31

i believe Alex means that if you close the in-ch elsewhere, then your if-some will be false and your go-loop will stop on its own. you shouldn’t close in-ch from looper

(def looper
  (go-loop []
    (if-some [val (<! in-ch)]
      (do
        (>! out-ch val)
        (recur))
      (println "in-ch has closed, looper exiting"))))

;; separately
(put! in-ch 9)
(close! in-ch) ;; causes looper to stop

drewverlee16:12:02

awesome, yep that makes sense to me.

drewverlee16:12:06

brb. thanks for the help 🙂