Fork me on GitHub
#cljs-dev
<
2020-02-17
>
dnolen13:02:16

@borkdude does that compile w/ warnings?

borkdude13:02:03

it doesn't compile, it throws at the analysis stage, you can't execute it.

borkdude13:02:03

I might have a look at it, but probably not before ClojureD

borkdude13:02:14

For now I just changed my macro into two macros

mfikes14:02:13

But @borkdude that’s not supposed to work, right? (It defines a macro and then uses it from the same namespace.)

mfikes14:02:24

(The arity is always wrong—it only has a runtime check that you see when a multiarity definition is involved.)

mfikes14:02:50

The reason you are seeing -1 has to do with the missing two hidden parameters the compiler supplies. (1 - 2 = -1)

Roman Liutikov14:02:12

@mfikes one is &env, what's the other one?

Roman Liutikov14:02:29

What's the use case for &form?

mfikes14:02:09

It is less used. ClojureScript is just following Clojure for this, FWIW.

mfikes14:02:28

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.

bronsa14:02:47

grabbing its meta

👍 4
borkdude14:02:35

@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

mfikes14:02:06

The str macro is one, for example...

mfikes14:02:18

That code shouldn't work in normal CLJS, right?

mfikes14:02:37

Fundamentally, it is a question of defining a macro in a macros namespace and then using it from a consuming namespace.

borkdude14:02:55

let me just get the failing code

mfikes14:02:06

By "shouldn't work in normal CLJS", I should have said "has undefined behavior in normal CLJS"

borkdude14:02:17

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

borkdude14:02:29

the diff contains more stuff, but that's one of the things I did

borkdude15:02:25

@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?

bronsa15:02:38

is that not shadowing foo/multi-arity-macro (macro) with foo/multi-arity-macro (fn) ?

mfikes15:02:39

Isn't that code calling the macro in the same namespace when definining it (and yet again later in the runtime namespace)?

Roman Liutikov15:02:21

yeah defmacro should go into reader conditional :clj

borkdude15:02:06

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)))

borkdude15:02:16

but that doesn't prevent the error from happening in self-hosted CLJS

Roman Liutikov15:02:20

or not? 🙂 I think ns gets $macros suffix...

mfikes15:02:22

@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.

👍 4
mfikes15:02:25

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.

borkdude15:02:46

so just moving the macro to a .clj file will probably work, ignoring the intricacies of .cljc and self-hosted?

mfikes15:02:01

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.

borkdude15:02:27

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]

borkdude15:02:46

which reflects what I had in my project, so the issue must be somewhat more subtle

borkdude15:02:06

I'll close the issue and I'll report again when I have more info