Search code examples
clojurethread-safetythreadpoolclojurescriptcore.async

core.async go block with outside bound symbols works but does not macroexpand


for the past few weeks I’ve been working with “core.async” in Clojure and Clojurescript, wondering if it is a good idea to use outside bound symbols inside a go as there is a pool of threads and possibly any of these could use the bound symbols. It works evaluating it, but macroexpansion does not work - see the following snippets

I guess it should work without problems. The x is immutable and wont change by concurrent threads. Using an atom as x for mutable data should also work cause its an atom XD E.g. an object ref would not work of course or could make problems!

(let [x 5]
  (clojure.core.async/go
   (println x)))

;; => 5
;; nil
(clojure.walk/macroexpand-all
   '(let [x 5]
      (clojure.core.async/go
        (println x))))

;; => Syntax error macroexpanding clojure.core.async/go at (your_project.cljc:93:3).
;;    Could not resolve var: x

It seems to work, but is it a bad idea and why?

Anyone can explain why macroexpansion does not work?


Solution

  • macroexpand-all is not a high-fidelity expander. It uses a basic process that works for simple macros, but it doesn't do everything the actual compiler does. Notably, it does not curate the &env map that bindings should introduce. I assume core.async needs to look at &env to determine whether a binding is local or a var.

    So, you shouldn't expect macroexpand-all to work here, but there's nothing wrong with writing code of this sort.