I’m looking to convert some macros for usage with sci. See https://github.com/sicmutils/sicmutils/pull/216. I first tried the copy-var approach, that seemed to work fine from Clojure, but not from ClojureScript. Now I’m trying to convert them but not clear on what I need to do.
@mkvlr Can you make a small example which allows me to explain how to solve that small example?
@borkdude sure, or do you have some good pointers of macros you converted for sci?
@mkvlr sci.impl.namespaces
has lots of those.
many of those have _ _
as the first two args, this is how you can find them
in general, a macro is nothing but a function that receives some forms and returns some other forms
but it has two extra arguments: form and env, but often these are not used. so they are named _ _
a common problem with copying macros is that the source macro is defined in a different namespace than the namespace of the sci environment
so the source macro expands into the wrong namespaced symbols
I usually solve this by copying the macro and fully qualifying all symbols myself
oh, but I can use quoting and splicing normally?
yes, but the syntax quote will resolve the symbols into the namespace where the macro is defined. so this is often the mismatch
syntax-quote is handled at clojure read-time, not at sci evaluation time
ok, so just fully-qualify it
so:
(ns foo)
(defn foo [_ _] `x)
will expand into (defn foo [_ _] 'foo/x)
. If your sci namespace is then called bar
and you add this macro to it, then you will have a mismatchand you recommend copying, right? It’s a bit too much of a head-bender for me how this works in ClojureScript with copy-var
copying is done to make the thing a var inside sci, so everything var-related works on it. But sci also allows you to just pass the function reference in the namespaces option
if vars aren't important to your sci usage, then you can just avoid using sci/copy-var
some people (in babashka for example) want to be able to use doc
, alter-var-root!
, with-redefs
, etc
but it will make doc etc work, right? So it’s a plus?
it depends. it might also come with some more overhead because on every call the var has to be dereferenced.
I'm thinking of a couple of optimizations here:
- https://github.com/borkdude/sci/issues/483
- add :direct-linking
option (or allow this programmatically from within a sci program)
but I think deref-ing a sci var is cheap
will have to do some benchmarks
in CLJS people are used to not having vars at runtime anyway
unless you're in self-hosted
so it's a bit of a grey area
for macros it's not so important, since macros are usually not re-defined
I think I have in fact a couple of macros in sci that aren't vars (just because I didn't bother to make them vars)
in short: doing {:namespaces {'foo (with-meta foo {:sci/macro true})}}
is fine
^ @mkvlr
hmm, and this should work from both Clojure + ClojureScript?
trying…
yes
(defn make-sci-namespace [ns-name]
(into {} (map (fn [[var-name the-var]]
(println var-name)
[var-name (cond-> @the-var
(-> the-var meta :macro)
(with-meta {:sci/macro true}))])) (ns-publics ns-name)))
trying this approach now…
but getting stuck on let-coordinates
which is imported https://github.com/sicmutils/sicmutils/blob/master/src/sicmutils/env.cljc#L346
ok, but this should work where it’s defined and then just copy it over
indeed there it does work
ok, 💯 I think I’m good
@borkdude I have all my sci namespaces as a map now, but trouble calling my macro. It works from Clojure but not from ClojureScript…
can you repro this?
if you want I can also do a short video call now
oh yes please
ok just a minute