cljs-dev

ClojureScript compiler & std lib dev, https://clojurescript.org/community/dev
dnolen 2020-02-17T13:22:16.016500Z

@borkdude does that compile w/ warnings?

borkdude 2020-02-17T13:25:03.017Z

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

borkdude 2020-02-17T13:25:51.017200Z

Posted an issue about it here: https://clojure.atlassian.net/browse/CLJS-3212

dnolen 2020-02-17T13:29:47.017700Z

k thanks

borkdude 2020-02-17T13:30:03.018Z

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

borkdude 2020-02-17T13:30:14.018300Z

For now I just changed my macro into two macros

mfikes 2020-02-17T14:30:13.019700Z

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

mfikes 2020-02-17T14:32:24.021900Z

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

mfikes 2020-02-17T14:33:50.023300Z

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

2020-02-17T14:35:12.023700Z

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

mfikes 2020-02-17T14:35:37.023900Z

&form

2020-02-17T14:35:53.024100Z

TIL

2020-02-17T14:38:29.024500Z

What's the use case for &form?

mfikes 2020-02-17T14:39:09.024900Z

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

mfikes 2020-02-17T14:40:28.025800Z

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.

bronsa 2020-02-17T14:40:47.026Z

grabbing its meta

๐Ÿ‘ 1
bronsa 2020-02-17T14:41:05.026200Z

logging

borkdude 2020-02-17T14:53:35.027300Z

@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

mfikes 2020-02-17T14:55:06.027700Z

The str macro is one, for example...

mfikes 2020-02-17T14:55:18.028100Z

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

mfikes 2020-02-17T14:55:37.028800Z

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

borkdude 2020-02-17T14:55:55.029Z

let me just get the failing code

mfikes 2020-02-17T14:57:06.029800Z

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

borkdude 2020-02-17T14:57:17.030100Z

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

borkdude 2020-02-17T14:57:29.030400Z

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

borkdude 2020-02-17T15:00:25.031Z

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

bronsa 2020-02-17T15:01:38.032100Z

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

mfikes 2020-02-17T15:01:39.032200Z

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

2020-02-17T15:02:21.032800Z

yeah defmacro should go into reader conditional :clj

borkdude 2020-02-17T15:03:06.034400Z

it is, that's why I also wrap this macro in my project:

(defmacro deftime
  "Private. deftime macro from <https://github.com/cgrand/macrovich>"
  [&amp; body]
  (when #?(:clj (not (:ns &amp;env))
           :cljs (when-let [n (and *ns* (ns-name *ns*))]
                   (re-matches #".*\$macros" (name n))))
    `(do ~@body)))

borkdude 2020-02-17T15:03:16.034900Z

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

2020-02-17T15:03:20.035200Z

or not? ๐Ÿ™‚ I think ns gets $macros suffix...

mfikes 2020-02-17T15:03:22.035300Z

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

๐Ÿ‘ 1
bronsa 2020-02-17T15:03:32.035700Z

TIL

mfikes 2020-02-17T15:04:25.036700Z

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.

borkdude 2020-02-17T15:06:46.037300Z

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

mfikes 2020-02-17T15:08:01.038300Z

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.

borkdude 2020-02-17T15:15:27.039500Z

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 <https://github.com/cgrand/macrovich>"
  [&amp; body]
  (when #?(:clj (not (:ns &amp;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=&gt; (require '[foo.core :as foo] :reload)
nil
cljs.user=&gt; (foo/foo)
[1]

borkdude 2020-02-17T15:15:46.039900Z

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

borkdude 2020-02-17T15:16:06.040200Z

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