Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why "Assert failed: >! used not in (go ...) block"

I am trying to figure out core.async in my REPL and am completely confused as to how my usage of (go-loop ...) doesn't manage to qualify as a "go block" for the purpose of async/>!

My go-loop is like...

(async/go-loop [page (range 3)]
  (if (empty? page)
    (async/close! ch)
    (dorun (map (fn [row]
                  (println row)
                  (async/>! ch row)) page)))
  (recur (range (dec (count page)))))

But the REPL is all upset...

=>
#object[clojure.core.async.impl.channels.ManyToManyChannel
        0x23465937
        "clojure.core.async.impl.channels.ManyToManyChannel@23465937"]
0
Exception in thread "async-dispatch-12" java.lang.AssertionError: Assert failed: >! used not in (go ...) block
nil
...

Why isn't the scope of that (go-loop ...) sufficient for the (async/>! row) call?

Should I even be using a go-loop here?

like image 573
Bob Kuhar Avatar asked Jan 29 '23 16:01

Bob Kuhar


1 Answers

>! and other parking calls can't be used inside of functions nested inside of a go unfortunately.

go turns the code you give it into a state machine and looks for parking calls. It doesn't however look inside of nested functions.

From Clojure.Asyncs Github best practice page:

Unsupported constructs and other limitations in go blocks

The go macro stops translating at function creation boundaries. This means the following code will fail to compile, or may just throw a runtime error stating that <! was used outside of a go block:

(go (let [my-fn (fn [] (<! c))]
    (my-fn)))

This is one thing to remember since many Clojure constructs create functions inside macros. The following are examples of code that will not work as one would expect:

(go (map <! some-chan))
(go (for [x xs]
      (<! x)))
like image 79
Carcigenicate Avatar answered Feb 04 '23 03:02

Carcigenicate