Can anyone point to some code that has #sci AND #clojure / #clojurescript compatible macros? Is there an easy trick to it? For instance, writing macros for #sci requires writing a ^:sci/macro function, whereas for normal clj/cljs it requires a normal macro written in clj. There's no #?(:sci ...) .cljc reader conditional (as far as I am aware (yet)). So curious if there is a best practice here to ship a library that is sci/#babashka / #clojure / #clojurescript compatible?
@goomba It depends what you want to achieve. In bb and clojure there are no differences between macros
But since there is no guarantee that a macro exists as a compiled thing in JS once you compiled your CLJS you often have to copy the macro code to a .cljs file if you want to configure it to work with SCI as pre-compiled macros. There is AFAIK no way around this.
But nbb, which is made with SCI, can run macros from source as well
So this is the config for promesa, which is a macro-heavy library: https://github.com/babashka/sci.configs/blob/main/src/sci/configs/funcool/promesa.cljs This configured is re-used in #scittle and #nbb and some other projects
Interesting. Now something like this: https://github.com/babashka/sci.configs/blob/main/src/sci/configs/funcool/promesa.cljs#L143 I'm assuming that will be treated like a regular function in a non sci context?
Yes
worrrd
ok that makes that easy
just write all macros like that
except in JVM clojure
there they behave like proper macros
but this is a .cljs file so it's just different there
I am a little unclear how macros work in sci with cljs.
(def do-twice ^:sci/macro (fn [_&form _&env x] (list 'do x x)))
That seems okay, but:
(sci/eval-string "(do-twice (f))" {:bindings {'do-twice do-twice 'f #(println "hello")}})
I can see how that would work with one use of do-twice in the eval string, but what if there is more than one?
Do you mean with more than one:
(do-twice (f))
(do-twice (f))
?Yes, perhaps with different arguments.
Why would that be a problem?
I must be missing something. The :bindings map seems to be referring to a single use of macro.
No, the bindings map is just a map of symbol to function
And this function (macro) can be called as many times as you want
I think maybe it is the 'f in the map that is is throwing me off.
ok, yeah, f is just a function reference
Similar to this:
(def f #(println :hello))
(f) (f) (f)But now as {'f #(println :hello)}
Got it. Thanks!