Fork me on GitHub
Jon Eskin08:02:21

If any Emacs users are using deps-new or clj-new, I made a wrapper with a Magit-style interface for using them within Emacs to create projects. I included a couple cool templates I've come across but I'm looking for worthy additions if anyone knows any 🙂

🙌 1

Nice. You should probably put this in #announcements rather than here.


Anyone have experience building jars in GitHub Actions CI? I'm trying to make a workflow to build a jar file, but the compilation fails in GitHub Actions but runs fine locally.

Run clojure -T:build uber
  clojure -T:build uber
  shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}
    JAVA_HOME: /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/11.0.14-101/x64
    CLOJURE_INSTALL_DIR: /opt/hostedtoolcache/ClojureToolsDeps/1.10.3-1029-3-6/x64/lib/clojure

... Download deps ...

Execution error (IOException) at (
No such file or directory

Full report at:
 "Execution error (ExceptionInfo) at (compile_clj.clj:92).\nClojure compilation failed\n",
 {:clojure.error/class clojure.lang.ExceptionInfo,
  :clojure.error/line 92,
  :clojure.error/cause "Clojure compilation failed",
  :clojure.error/source "compile_clj.clj",
  :clojure.error/phase :execution},
  [{:type clojure.lang.ExceptionInfo,
    :message "Clojure compilation failed",
    :data {},
   [clojure.lang.Var invoke "" 384]
   [$compile_clj invokeStatic "api.clj" 232]
   [$compile_clj invoke "api.clj" 209]
   [$uber invokeStatic "build.clj" 248]
   [$uber invoke "build.clj" 209]
   [build$uber invokeStatic "build.clj" 11]
   [build$uber invoke "build.clj" 10]
   [clojure.lang.AFn applyToHelper "" 154]
   [clojure.lang.AFn applyTo "" 144]
   [clojure.lang.Var applyTo "" 705]
   [clojure.core$apply invokeStatic "core.clj" 667]
   [clojure.core$apply invoke "core.clj" 662]
   [$exec invokeStatic "exec.clj" 48]
   [$exec doInvoke "exec.clj" 39]
   [clojure.lang.RestFn invoke "" 423]
   [$_main$fn__205 invoke "exec.clj" 178]
   [$_main invokeStatic "exec.clj" 174]
   [$_main doInvoke "exec.clj" 139]
   [clojure.lang.RestFn applyTo "" 137]
   [clojure.lang.Var applyTo "" 705]
   [clojure.core$apply invokeStatic "core.clj" 667]
   [clojure.main$main_opt invokeStatic "main.clj" 514]
   [clojure.main$main_opt invoke "main.clj" 510]
   [clojure.main$main invokeStatic "main.clj" 664]
   [clojure.main$main doInvoke "main.clj" 616]
   [clojure.lang.RestFn applyTo "" 137]
   [clojure.lang.Var applyTo "" 705]
   [clojure.main main "" 40]],
  :cause "Clojure compilation failed",
  :data {}}}

Execution error (ExceptionInfo) at (compile_clj.clj:92).
Clojure compilation failed

Error: Process completed with exit code 1.

Alex Miller (Clojure team)14:02:34

I assume this works if you run it locally?

Alex Miller (Clojure team)14:02:24

this is a pretty old version of now, and I have fixed some bugs and error reporting in compile-clj since then, although not sure anything of that is related


Yea, runs as expected locally. I'll try upgrading the vresion of :thumbsup:

Alex Miller (Clojure team)14:02:14

my 2 initial hypotheses are: • something to do with creating the temp dir where compile-clj does its compiling • something in your code that creates a dir in top-level side-effecting def during compiling which works locally but doesn't elsewhere


Okay, so updating tools.deps doesn't do it. Would this likely be the issue then? This file creates some files at the top-level

Alex Miller (Clojure team)15:02:28

if any of those dirs doesn't exist or you don't have perms, it would fail like this

Alex Miller (Clojure team)15:02:40

generally side effecting code in defs like this is bad (as it is run during compilation)


Ahh, I didn't realize that would be run during compilation. I'll change this up and add the checks to setup the files/directories elsewhere.

Alex Miller (Clojure team)15:02:01

compilation just is a side effect of load, so all the code you compile will be loaded


Ahh that fixed it! Still got other issues in my CI, but the jar compiles fine now! Thank you so much!

Alex Miller (Clojure team)15:02:48

in the future, feel free to ask on #tools-build instead...


Will do :thumbsup: I looked for a general CI channel or github actions one, but only saw specific CircleCI so I wasn't sure where best to ask.

eccentric J15:02:36

A coworker is asking if there's any Clojure projects in the wasm space. Anything come to mind? Recall hearing a bit about that a few years ago


I’m curious about this myself. I can call WASM via the Java and JavaScript interop, but don’t know of any libraries that make this easier (I’ve been considering writing a utility for this). I’d love to see Clojure compile to WASM, but since there isn’t an official GC in WASM that isn’t really feasible for the moment.


I guess theres but only deals with manipulating the WASM file.

eccentric J15:02:09

Found and if projects like Babashka or Node Babashka use graal and graal can target WASM then that could be a suitable pipeline


wasm has no gc so it doesn't really make sense


There are GCs being developed, but they’re not there yet. And I don’t see them being anywhere near as good as Shenandoah


Liz has a clojure like syntax and is transpiled to zig, so can be compiled to wasm


i would like to see some kind of typed clojure for wasm, something like assemblescript


What's a performant way to get all the :foo and :bar keys at once, grouped into two vectors?

(let [[foos bars] (mystery-fn [{:foo 1 :bar 2} {:foo 3 :bar 4}])]
  (is (= [1 3] foos))
  (is (= [2 4] bars)))
with little/no intermediate collections


How do you know you'll get [foos bars] and not [bars foos]? Sorry if this is a noob question, I assumed it's not deterministic


depends on mystery-fn :) its signature could be (mystery-fn [:foo :bar] coll) and the [:foo :bar] order would be honored


faster than:

[(mapv :foo coll) (mapv :bar coll)]


I ended up doing sth to that effect, however traversing the coll N times might have some performance impact I had in mind a fn that would traverse the coll just once, building N transient vectors that would grow as the traversal progresses


yeah I tried that on repl, I think it might end up being slower for small N keywords


at least was slower on my computer for the foo/bar example:

(defn mystery-fn2
  (loop [foos (transient [])
         bars (transient [])
         rem coll]
    (if-not (seq rem)
      [(persistent! foos) (persistent! bars)]
      (let [i (first rem)]
        (recur (conj! foos (:foo i))
               (conj! bars (:bar i))
               (rest rem))))))
also not really extensible to N keywords, maybe a reduce with a map {key transient-coll}


rest uses the seq abstraction, which is sometimes slower than reducing over the same coll


(further optimize at your own discretion - probably my code will remain as-is ;p)

👌 1

or (reduce (fn [a m] (reduce (fn [a [k v]] (update-in a [k] (fnil conj []) v)) a (keys m)) {} ...)


I usually think of that kind of operation as being "facet" because the first time I saw it pulled out as a reusable pattern was

🙂 1

Why is :y 2 in the result there? Shouldn't it be 2.5?


TIL! perhaps I'll keep my code dumb for now - partly I was asking to make sure I wasn't just forgetting some basic idiom


Basically juxt for folds


Is it poor form to include percent signs in symbol names? For example: foo% meaning the percentage of foo.

😐 1

seems reasonable to me


Thanks. Looks like folks on my team are already using foo-pct so I’ll go with that. I prefer to stick with conventions when they are established even if they aren’t how I’d normally do things.

👍 2

i bet people are generally unaware that you can use % in a symbol


It already breaks a lot of people’s brains that you can use *?! in symbols


You can technically use . in clj, but it breaks in shadow-cljs


percent of what? Maybe you can just do foo÷bar


that way the name of the numerator and the denominator are preserved


@U3JH98J4R Naming it foo-ratio was one of the suggestions.

Björn Ebbinghaus16:02:04

I would argue, that percent = ratio * 100 So a number „in percent“ is different to the ratio.