A possible solution to avoid limitation in go macro: Must be called inside a (go ...) block

StackOverflow https://stackoverflow.com/questions/19538919

  •  01-07-2022
  •  | 
  •  

Question

Perhaps a possible solution to use (<! c) outside go macro could be done with macro and its macro expansion time :

This is my example:

(ns fourclojure.asynco
      (require [clojure.core.async :as async :refer :all]))

(defmacro runtime--fn [the-fn the-value]
  `(~the-fn ~the-value)
  )
(defmacro call-fn [ the-fn]
  `(runtime--fn ~the-fn (<! my-chan))
  )

(def my-chan (chan))

(defn  read-channel [the-fn]
  (go
  (loop []
    (call-fn the-fn)
    (recur)
    )
  ))

(defn paint []
  (put! my-chan "paint!")
  )

And to test it:

(read-channel print)
(repeatedly 50 paint)

I've tried this solution in a nested go and also works. But I'm not sure if it could be a correct path

The reason about this question is releated to this other question Isn't core.async contrary to Clojure principles?, @aeuhuea comment that "It seems to me that this prevents simplicity and composability. Why is it not a problem?" and @cgrand response "The limitation of the go macro (its locality) is also a feature: it enforces source code locality of stateful operations." But force to localize your code is not the same as "complect"?

Was it helpful?

Solution

Regarding the title of your question:

>!must be called in a go block because it's designed to. If you are interested in the go-block state-machine mechanics, I can highly recommend Timothy Baldridges Youtube videos on that http://www.youtube.com/channel/UCLxWPHbkxjR-G-y6CVoEHOw

Remember that there is always blocking take and put >!! and <!!. I don't know which part of your code is supposed to provide a "solution" for not being able to use <! and >! outside of a go block, however looping around events dispatched from a single channel is common practice. Here is a modified version of read-channel

(defn do-channel [f ch]
  (go-loop []
    (when-let [v (<! ch)]
      (f v)
      (recur))))

put! puts asynchronously, an effect that you usually don't intend. In your example, to put the string "paint" into the channel 50 times, I'd recommend a one-liner like this one:

(do-channel println (to-chan (repeat 50 "print")))

Here is a comment as an answer to your edit: Channels are not designed to be used as mutable data-structures, period. They have a buffer and that buffer can be thought of as a mutable queue. However we don't use channels to store a value in there, just to take it out a few lines later again. We use channels as helping construct that may be used to bring execution of two or more different pieces of source-code in two or more different places in line. E.g. a go-block here does not continue to execute until it has received a value produced by another go-block. >! and >!! help us to distinguish whether they are used in a thread-blocking context or in a go-block (blocking a spawned process).

Also, please refer to this answer: Clojure - Why does execution hang when doing blocking insert into channel? (core.async)

You should not use >!! or <!! inside of a go-block, neither transparently or nested in a function call. Rich Hickey himself has commented on that in a recent bug report (http://dev.clojure.org/jira/browse/ASYNC-29?focusedCommentId=32414&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-32414).

Looking at the source-code of >! you will see that it only throws an exception. As a matter of fact, go will replace >! with different source-code. go spawns a state-machine controlled process. Depending on the context you may want to make this explicitly known or nest the go block inside of a macro or function (like in the code examples that you have provided).

Regarding David Nolens (swannodettes) helpers: They have been implemented by Rich Hickey and Nolen himself into the core.async library. Nolen said himself that they are superseded in this presentation (http://www.youtube.com/watch?v=AhxcGGeh5ho). Notice that go-loop has been implemented since after Nolens commit.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top