Fork me on GitHub
#cljs-dev
<
2022-09-29
>
mkvlr04:09:22

@shaunlebron the reader macro metadata isn't evaluated: > Note that metadata reader macros are applied at read-time, not at evaluation-time from the end of https://clojure.org/reference/metadata If you want it to be evaluated use e.g. with-meta or vary-meta

thheller05:09:49

yeah, the ^js/React.Element there becomes the :tag meta of the (provider) list. which the compiler will then apply as the :tag in the AST and used for analysis (eg. inference) purposes

shaunlebron15:09:22

Hmm, so how does ^js [] not work if ^js () does? (Neither work in clojure btw.)

thheller15:09:58

clojure will always resolve tags during compilation, since it wants to map for actual JVM things (eg. classes). CLJS almost never resolves tags at all, not even sure if ever.

p-himik15:09:11

ClojureScript 1.11.60
cljs.user=> (let [a 1] (meta ^a []))
{:tag 1}

👀 1
thheller15:09:44

sorry, should have qualified. resolves tags for vars

p-himik15:09:29

Ah, right.

thheller15:09:02

hmm maybe it does? I thought all analyzer metadata is dropped when generating code

thheller15:09:05

ok, I guess it really does resolve those. just not for vars then

bronsa15:09:22

it's not quite that

bronsa15:09:30

metadata on def symbols is not evaluated

bronsa15:09:38

but on expressions it is

bronsa15:09:44

^foo expr is compiled more or less like if it was (with-meta expr foo)

thheller15:09:45

yeah but I thought it dropped tag info just like it drops all other reader metadata (line, col, etc)

thheller15:09:55

guess it does not

shaunlebron16:09:17

ClojureScript 1.11.60
cljs.user=> (meta ^js [])
WARNING: Use of undeclared Var cljs.user/js
{:tag nil}
cljs.user=> (meta ^js ())
{:tag js}

shaunlebron16:09:03

@U060FKQPN: i think the rule is that cljs evals metadata on all expressions except lists

thheller16:09:37

I think empty list is just a special case

shaunlebron16:09:16

right i think it blocks metadata eval on lists for invoke exprs, and happens to catch the empty list case

p-himik16:09:29

From that code, it seems as if the tag should've been replaced with cljs.core/IList. Why is it still js then?

thheller16:09:02

I'm guessing the infer-type analyzer pass just overrides it again. since that just looks at the unevaluated form

p-himik16:09:07

Hmm. Or maybe :tag after that point differs from (meta form).

shaunlebron18:09:36

Does this work for documentation? > Values provided inside metadata reader macros in ClojureScript are only evaluated when they precede evaluated collection literals— except lists.

p-himik18:09:24

I'll give you one more:

cljs.user=> (let [a 1] (meta ^a ()))
{:tag a}
cljs.user=> (let [a 1] (meta ^a '()))
nil
:D (probably because '() is actually (quote ()) which is not () by itself)

shaunlebron18:09:45

I think the description still works for that then! right?

shaunlebron18:09:28

^a was attached to the quote form unevaluated, then quote evaluated to () with no metadata

shaunlebron19:09:10

err, quote wasn’t evaluated, I mean compiled probably

shaunlebron19:09:37

I modified the description to account for this:

(defn foo ^a [] 1)

shaunlebron19:09:03

[] is a collection literal but is unevaluated

p-himik19:09:13

Honestly, I have no idea how to describe all this without it becoming even more confusing to a reader.

shaunlebron19:09:27

I agree, but I only went down here because I saw ^js and realized my ^meta docs were wrong about evaluating symbols

shaunlebron19:09:58

I won’t put it front and center summary, but it should be a footnote in the details

thheller19:09:51

I think the relevant bit is whether the "thing" ends up as a runtime thing, or is just "syntax" (ie. for macros)

shaunlebron19:09:19

yeah I like that

thheller19:09:26

so in defn the ^a [] never ends up anywhere in the code. it is just used by the analyzer to define the return type

thheller19:09:18

it still is just a vector with :tag a meta, but since it never ends up in the runtime its never evaluated and thus not resolved

shaunlebron19:09:57

okay, so anytime metadata reader macros are used on values available to the runtime, it’s evaluated.

shaunlebron19:09:32

and maybe not mention the empty list exception

thheller19:09:11

there are other exceptions but yes

thheller19:09:18

is this still related to the ^js docs? I don't think this is relevant to any of that at all. there are really only a couple places ^js should be used. maybe should just add the 3 examples for that or so? 😛

shaunlebron19:09:51

yeah I wouldn’t put any of this in the ^js doc

👍 1
shaunlebron19:09:17

I realized last month that my ^meta doc was wrong though: https://github.com/cljs/api/issues/187

shaunlebron19:09:53

I said something like ^foo => ^{:tag <value at foo>}, so that’s what I’m trying to clear up there

shaunlebron20:09:36

> I think the relevant bit is whether the "thing" ends up as a runtime thing, or is just "syntax" (ie. for macros) So anytime ^a foo can be emitted as (with-meta foo {:tag a}) , you can know a is evaluated?

thheller20:09:47

well thats a bad example since foo is a symbol and never actually ends up in the code 😛

p-himik20:09:13

Feels like all these metadata threads are a perfect source of materials for some Clojure quiz. :D

😄 1
shaunlebron20:09:38

@U05224H0W dang you’re right, just when I think I understand something:

cljs.user=> (let [a 1 foo []] (with-meta foo {:tag a}))
^{:tag 1} []
cljs.user=> (let [a 1 foo []] ^a foo)
[]

shaunlebron20:09:34

I don’t think there’s a clear rule then, not one I can write at least

thheller20:09:09

well the rule is that the metadata is always applied to what is read, so symbols, lists, etc

thheller20:09:17

what happens with that depends on the context 😛

👍 1
shaunlebron20:09:01

right, so the rule for the context would be too complicated?

thheller20:09:01

well if you want to explain macros? 😛 can't really come up with a way to explain it simply

thheller20:09:06

I never use it for runtime stuff, so I consider it a syntax only thing for the compiler

shaunlebron20:09:51

Is there a way to show code emitted from the repl?

shaunlebron20:09:50

oh nice, :repl-verbose

thheller20:09:11

see the "Generated JS" tab

shaunlebron21:09:25

Strange, the verbose option for repl doesn’t seem to work for me:

$ clj -M -m cljs.main --repl-opts "{:repl-verbose true}" --repl

thheller21:09:11

don't know what :repl-verbose is supposed to do

thheller21:09:54

ah. yeah dunno. not something shadow-cljs supports either 😛

quoll21:09:47

That’s OK. There’s always *print-fn-bodies* 🙂

👍 1
shaunlebron21:09:14

thanks, that works!

ClojureScript 1.11.60
cljs.user=> (set! *print-fn-bodies* true)
true
cljs.user=> (fn [] (let [a 1] ^a []))
#object[ret__7815__auto__ "function (){
var a = (1);
return cljs.core.with_meta(cljs.core.PersistentVector.EMPTY,new cljs.core.PersistentArrayMap(null, 1, [new cljs.core.Keyword(null,"tag","tag",-1290361223),a], null));
}"]

quoll21:09:22

@U04VDQDDY taught me that one (thank you Mike!)

👍 1
shaunlebron23:09:49

I added the simplest possible note as I could on this stuff here: http://cljs.github.io/api/syntax/meta