This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-02-17
Channels
- # announcements (1)
- # aws (40)
- # babashka (37)
- # beginners (305)
- # chlorine-clover (15)
- # cider (5)
- # cljs-dev (40)
- # clojure (62)
- # clojure-europe (13)
- # clojure-nl (4)
- # clojure-spec (10)
- # clojure-sweden (2)
- # clojure-uk (59)
- # clojurescript (9)
- # core-async (13)
- # cursive (5)
- # data-science (2)
- # datascript (2)
- # datomic (29)
- # emacs (8)
- # fulcro (58)
- # lambdaisland (9)
- # leiningen (2)
- # lumo (3)
- # mid-cities-meetup (1)
- # midje (1)
- # off-topic (28)
- # shadow-cljs (32)
- # spacemacs (3)
- # sql (5)
- # tools-deps (1)
- # tree-sitter (1)
- # vscode (2)
- # yada (2)
Posted an issue about it here: https://clojure.atlassian.net/browse/CLJS-3212
But @borkdude that’s not supposed to work, right? (It defines a macro and then uses it from the same namespace.)
(The arity is always wrong—it only has a runtime check that you see when a multiarity definition is involved.)
The reason you are seeing -1 has to do with the missing two hidden parameters the compiler supplies. (1 - 2 = -1)
@mfikes one is &env
, what's the other one?
What's the use case for &form
?
I can't recall a use case for &form
off the top of my head. 🙂
I bet there is one out there in the wild.
@mfikes fwiw, this example is adapted from a codebase with a that works in normal CLJS, but just not in self-hosted CLJS (lumo, planck). if you can provide me with a multi-arity macro example that is supposed to work, that would be cool
Fundamentally, it is a question of defining a macro in a macros namespace and then using it from a consuming namespace.
By "shouldn't work in normal CLJS", I should have said "has undefined behavior in normal CLJS"
this is the diff I had to make to get it working with self-hosted CLJS:
https://github.com/borkdude/sci/commit/fac2aa8c43091da8aca0f7a45e7a417df0c2ad13#diff-2d9a9848391e25828d94fe11d6ed40d4
so I had to split the copy-var
macro into two macros
@mfikes :
(ns foo
#?(:require-macros [foo :refer [multi-arity-macro]]))
(defmacro multi-arity-macro
([x] [x])
([x y] [x y]))
(println (multi-arity-macro 1))
(println (multi-arity-macro 1 2))
$ plk -f /tmp/foo.cljc
WARNING: foo is a single segment namespace at line 1
Execution error (Error) at (<cljs repl>:1).
Invalid arity: -1
What about this example?Isn't that code calling the macro in the same namespace when definining it (and yet again later in the runtime namespace)?
yeah defmacro
should go into reader conditional :clj
it is, that's why I also wrap this macro in my project:
(defmacro deftime
"Private. deftime macro from "
[& body]
(when #?(:clj (not (:ns &env))
:cljs (when-let [n (and *ns* (ns-name *ns*))]
(re-matches #".*\$macros" (name n))))
`(do ~@body)))
or not? 🙂 I think ns gets $macros
suffix...
@bronsa In self-hosted ClojureScript, macros are defined in a separate synthetic pseudo namespace. (In this case named foo$macros
). So there can be two separate vars.
The need to do this arises in self-hosted because everything is executing in the same execution environment, whereas in JVM-based ClojureScript you have the JS / JVM barrier to keep things separate.
so just moving the macro to a .clj file will probably work, ignoring the intricacies of .cljc and self-hosted?
Yes, that would work with self-hosted, if I'm understanding what you are suggesting. The rule is simply that you need to define a macro in a macros namespace, but then call it from a runtime namespace, however you achieve that.
hmm, just fyi, this does seem to work: foo/macros.cljc:
(ns foo.macros
#?(:cljs
(:require-macros
[foo.macros :refer [deftime]])))
(defmacro deftime
"Private. deftime macro from "
[& body]
(when #?(:clj (not (:ns &env))
:cljs (when-let [n (and *ns* (ns-name *ns*))]
(re-matches #".*\$macros" (name n))))
`(do ~@body)))
foo.core:
(ns foo.core
(:require [foo.macros :as macros])
#?(:cljs (:require-macros [foo.core :refer [multi-arity-macro]])))
(macros/deftime
(defmacro multi-arity-macro
([x] `~[x])
([x y] `~[x y])))
(defn foo []
(multi-arity-macro 1))
REPL session:
$ plk
ClojureScript 1.10.520
cljs.user=> (require '[foo.core :as foo] :reload)
nil
cljs.user=> (foo/foo)
[1]