I’m encountering an odd issue with neanderthal and core.async. When neanderthal is included as a dependency alongside core.async, the io-thread macro (introduced in newer core.async versions) becomes unresolvable, even when explicitly specifying a recent core.async version that contains this macro. e.g.,
Working as expected:
clojure -Srepro -Sdeps '{:deps {org.clojure/core.async {:mvn/version "1.8.741"}}}' \
-M -e '(require (quote [clojure.core.async :as async])) (println (resolve (quote async/io-thread)))'
#'clojure.core.async/io-thread
Not working:
clojure -Srepro -Sdeps '{:deps {uncomplicate/neanderthal {:mvn/version "0.54.1"} org.clojure/core.async {:mvn/version "1.8.741"}}}' \
-M -e '(require (quote [clojure.core.async :as async])) (println (resolve (quote async/io-thread)))'
nil
I’m at a bit of a loss what may be causing this. Does anyone have any clues?
More in 🧵I could, but why? The only reason for bundling is the aot convenience. Otherwise, the user uses just one or two separate dependencies that they actually need (for example, only org.uncomplicate/neanderthal-mkl)...
Here’s the -Stree output with neanderthal + explicit core.async
The dependency tree shows the correct version is selected, so it’s not dep resolution that’s the cause here.
@blueberry suggested using non-AOT compiled deps, which exhibit the same behavior.
clojure -Srepro -Sdeps '{:deps {org.uncomplicate/neanderthal-base {:mvn/version "0.54.0"}
org.uncomplicate/neanderthal-openblas {:mvn/version "0.54.0"}
org.uncomplicate/neanderthal-mkl {:mvn/version "0.54.0"}
org.uncomplicate/neanderthal-opencl {:mvn/version "0.54.0"}
org.uncomplicate/neanderthal-cuda {:mvn/version "0.54.0"}
org.uncomplicate/neanderthal-accelerate {:mvn/version "0.54.0"}
org.clojure/core.async {:mvn/version "1.8.741"}}}' \
-M -e '(require (quote [clojure.core.async :as async])) (println (resolve (quote async/io-thread)))'
nilThat works for me:
(!2020)-> clojure -Srepro -Sdeps '{:deps {org.uncomplicate/neanderthal-base {:mvn/version "0.54.0"}
org.uncomplicate/neanderthal-openblas {:mvn/version "0.54.0"}
org.uncomplicate/neanderthal-mkl {:mvn/version "0.54.0"}
org.uncomplicate/neanderthal-opencl {:mvn/version "0.54.0"}
org.uncomplicate/neanderthal-cuda {:mvn/version "0.54.0"}
org.uncomplicate/neanderthal-accelerate {:mvn/version "0.54.0"}
org.clojure/core.async {:mvn/version "1.8.741"}}}' -M -e '(require (quote [clojure.core.async :as async])) (println (resolve (quote async/io-thread)))'
#'clojure.core.async/io-thread
but the original fails -- because the JAR includes an AOT compiled version of that older core.async> jar tvf ~/.m2/repository/uncomplicate/neanderthal/0.54.1/neanderthal-0.54.1.jar |fgrep async|more
1692 Mon Jul 07 08:27:08 EDT 2025 uncomplicate/clojurecuda/info$async_engine_count.class
2515 Mon Jul 07 08:27:08 EDT 2025 uncomplicate/clojurecuda/info$async_engine_count$fn__86114.class
610 Mon Jul 07 08:27:06 EDT 2025 clojure/core/async$mix$fn__84335$G__84199__84338.class
1793 Mon Jul 07 08:27:06 EDT 2025 clojure/core/async$fn__82981.class
1788 Mon Jul 07 08:27:06 EDT 2025 clojure/core/async$pipe.class
612 Mon Jul 07 08:27:06 EDT 2025 clojure/core/async$transduce$fn__83728$G__83708__83729.class
616 Mon Jul 07 08:27:06 EDT 2025 clojure/core/async$pipeline_STAR_$fn__83471$G__83407__83492.class
612 Mon Jul 07 08:27:06 EDT 2025 clojure/core/async$partition$fn__85295$G__85240__85302.class
605 Mon Jul 07 08:27:06 EDT 2025 clojure/core/async$map$fn__84688$G__84613__84689.class
2184 Mon Jul 07 08:27:06 EDT 2025 clojure/core/async$buffer.class
point_up::skin-tone-2 This is bad -- a library should never include AOT dependencies, IMO.... and it doesn't include aot deps by default. It's an option for users who want their engines to be instantiated quickly. Otherwise many heavy macros have to do their work, and many expressions need to be evaluated, which lasts 20-ish seconds. The users usually prefer to skip that and start developing in the REPL immediately. For production software they should of course use non-AOT compiled neanderhtal components that they want in their distribution. I'd love to be able to satisfy both use cases, and the only way I know is to offer both AOT compiled, and plain Clojure distributions. Never say never, I guess :)
Oh interestingggg. So I was running the clojure -Srepro -Sdeps … in a dir with a deps.edn file that must be causing it to print nil for me. I thought -Srepro would only use the -Sdeps map, but I should’ve ready the doc — it just ignores the home dir one. Whoops! Thank you folks - y’all are the best
@blueberry Ah, that context was not clear to me. I assumed org.uncomplicate/neanderthal was the "normal" dependency to use, rather than six separate dependencies. Could you perhaps have org.uncomplicate/neanderthal-aot for the AOT version (and without -aot being the "safe" bundled version?).
@kenny Yeah, -Srepro is intended to only ignore per-machine (user) config so a project's deps can be "repro'd" (but you're still dependent on the per-machine install of the CLI itself). -T runs without the project dependencies but wouldn't help you here. There's no option to ignore the project deps.edn (I think it would be quite useful).
I had the exact same read on the dep name as Sean.