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)
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)?
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 [email protected])))
@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 [email protected])))
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]