This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-12-03
Channels
- # adventofcode (91)
- # announcements (7)
- # aws (3)
- # babashka (69)
- # beginners (46)
- # calva (30)
- # cider (12)
- # clj-kondo (88)
- # cljs-dev (11)
- # cljsrn (1)
- # clojure (195)
- # clojure-dev (21)
- # clojure-europe (2)
- # clojure-italy (13)
- # clojure-nl (56)
- # clojure-spec (4)
- # clojure-sweden (6)
- # clojure-uk (27)
- # clojurescript (179)
- # core-async (2)
- # cryogen (1)
- # cursive (2)
- # data-science (1)
- # datomic (57)
- # fulcro (15)
- # graalvm (9)
- # instaparse (6)
- # joker (18)
- # juxt (9)
- # leiningen (6)
- # off-topic (20)
- # other-languages (10)
- # pathom (5)
- # re-frame (20)
- # reitit (2)
- # rewrite-clj (5)
- # shadow-cljs (78)
- # sql (34)
- # tools-deps (128)
- # uncomplicate (16)
- # vim (6)
bb var branch:
$ ./bb "(def x 10) (defn foo [] x) (def x 11) (println (foo)) #'foo"
11
#'foo
The grey areas of Clojure/Script:
cljs.user=> (defmacro ^:dynamic foo [])
#'cljs.user/foo
cljs.user=> (binding [foo 10] foo)
10
user=> (defmacro ^:dynamic foo [])
#'user/foo
user=> (binding [foo 10] foo)
Syntax error compiling at (REPL:1:1).
Can't take value of a macro: #'user/foo
for the cljs case, i've been unclear whether there is a canonical place to test this kind of thing -- somehow i have the impression that depending on which place this is tried the answer can differ (e.g. lumo, shadow-cljs, planck, etc.)
...and that repl appears to often be implemented differently in each of shadow-cljs, lumo, planck, etc., iiuc
right now it looks like this:
(defn new-var
"Returns a new sci var."
([name] (new-var name nil nil))
([name val] (new-var name val (meta name)))
([name init-val meta] (sci.impl.vars.SciVar. init-val name meta)))
(defn new-dynamic-var
"Same as new-var but adds :dynamic true to meta."
([name] (new-dynamic-var name nil nil))
([name init-val] (new-dynamic-var name init-val (meta name)))
([name init-val meta] (sci.impl.vars.SciVar. init-val name (assoc meta :dynamic true))))
But I already discovered this needs to change, because probably the namespace field should also be associated inI started with the Var definition of CLJS which doesn't seem to be doing that: https://github.com/clojure/clojurescript/blob/23cedecbf4f704f9fee672e395bbfa1e3fe3ee1a/src/main/cljs/cljs/core.cljs#L1118
that could work, since it's not really that important to which namespace a var belongs in sci
i guess the comparison is to this (Var.java)?
static Keyword privateKey = Keyword.intern(null, "private");
static IPersistentMap privateMeta = new PersistentArrayMap(new Object[]{privateKey, Boolean.TRUE});
static Keyword macroKey = Keyword.intern(null, "macro");
static Keyword nameKey = Keyword.intern(null, "name");
static Keyword nsKey = Keyword.intern(null, "ns");
so in CLJS there isn't an explicit namespace field in the type, but in CLJ there is: https://github.com/clojure/clojure/blob/653b8465845a78ef7543e0a250078eea2d56b659/src/jvm/clojure/lang/Var.java#L90
🐇 🕳️ that one means not going down at the moment, 🕳️ 🐇 this one means about to go down
I should probably add the *ns*
dynamic var and that should have some contents...
ClojureScript 1.10.520
cljs.user=> *ns*
#object[cljs.core.Namespace]
that is only used in self-hosted CLJS: https://github.com/clojure/clojurescript/blob/23cedecbf4f704f9fee672e395bbfa1e3fe3ee1a/src/main/cljs/cljs/core.cljs#L11560
what do people use *ns*
for in practice beyond inspecting what the current ns is? define vars in other namespaces?
except that it doesn't work:
$ clj -e "(binding [*ns* (find-ns 'clojure.core)] (def x 1))"
#'user/x
(do (in-ns 'user) (binding [*ns* (find-ns 'clojure.core)] (print *ns*)))
#object[clojure.lang.Namespace 0x1c801a1a clojure.core]
i happen to be reading eval() in Compiler.java and noticed that things that start with "def" seem to be special-cased -- not sure if that is related
https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L7172
but it's unclear to me where the Var argument gets created: https://github.com/clojure/clojure/blob/653b8465845a78ef7543e0a250078eea2d56b659/src/jvm/clojure/lang/Compiler.java#L424
it seems to be created in the aptly named method lookupVar... https://github.com/clojure/clojure/blob/653b8465845a78ef7543e0a250078eea2d56b659/src/jvm/clojure/lang/Compiler.java#L7458
this part is also interesting. it seems to be using a method called currentNS
, we're getting closer
ah: https://github.com/clojure/clojure/blob/653b8465845a78ef7543e0a250078eea2d56b659/src/jvm/clojure/lang/Compiler.java#L7518 it really seems to be using the dynamic var
this does work:
user=> (ns bar) (ns foo)
nil
nil
foo=> (set! *ns* (find-ns 'foo))
#object[clojure.lang.Namespace 0x485e36bc "foo"]
foo=> (set! *ns* (find-ns 'bar))
#object[clojure.lang.Namespace 0x17cdf2d0 "bar"]
bar=>
this method appears to be the only place that uses DefExpr: https://github.com/clojure/clojure/blob/653b8465845a78ef7543e0a250078eea2d56b659/src/jvm/clojure/lang/Compiler.java#L530
same thing for plk:
$ plk -e "(ns foo) (ns bar) (binding [*ns* (find-ns 'foo)] (def x 1))"
WARNING: foo is a single segment namespace at line 1
WARNING: bar is a single segment namespace at line 1
#'bar/x
$ /usr/local/bin/joker
Welcome to joker v0.12.4. Use EOF (Ctrl-D) or SIGINT (Ctrl-C) to exit.
user=> (set! *ns* (find-ns 'foo))
<repl>:1:2: Parse error: Unable to resolve symbol: set!
I'm not sure if it would be bad if babashka would return #'foo/x
, I might have to try hard to produce the same (unexpected for me) result of clojure and cljs
i'm not sure the current case is so common -- putting a def directly in the body of a binding.
could be handy to be able to search for such patterns across all of the latest clojars jars 🙂