Reputation: 850
I'm experimenting with ns
in Clojure, here's what I try:
user=> (in-ns 'some-ns)
#<Namespace some-ns>
some-ns=> (def aa 100)
#'some-ns/aa
some-ns=> (in-ns 'user)
#<Namespace user>
user=> (= some-ns/aa 100)
true
user=> (= user/aa 100)
CompilerException java.lang.RuntimeException: No such var: user/aa, compiling:(NO_SOURCE_PATH:5:1) ;this works as expected
user=> (defn function [] (in-ns 'some-other-ns) (def cc 100) (in-ns 'user))
#'user/function
user=> (function)
#<Namespace user>
user=> (= some-other-ns/cc 100)
CompilerException java.lang.RuntimeException: No such var: some-other-ns/cc, compiling:(NO_SOURCE_PATH:8:1)
user=> (= user/cc 100)
true
I'm confused, why it doesn't work in function? Also, I tried following:
user=> (binding [*ns* (create-ns 'some-a-ns)] (def dd 100))
#'user/dd
user=> (= some-a-ns/dd 100)
CompilerException java.lang.RuntimeException: No such var: some-a-ns/dd, compiling:(NO_SOURCE_PATH:11:1)
user=> (= user/dd 100)
true
according to clojure doc
Creates and interns or locates a global var with the name of symbol and a namespace of the value of the current namespace (*ns*).
what I'm missing?
PS. I know I can use (intern 'some-ns 'a 100)
, but what I really want is a generic function/macro to do like
(with-ns 'some-ns (def a 100))
(= some/a 100)
Upvotes: 3
Views: 1458
Reputation: 84331
intern
is the correct solution and you can use it in any functions / macros of your own. (Functions can call intern
; macros can expand to code calling intern
.)
def
should only ever be used directly at top level or nested within top-level forms where it will be immediately executed as soon as the top-level form is. So, def
in let
is fine, def
inside a function is not.
def
receives special handling from the compiler in that the Vars defined by def
forms are actual created as soon as the def
is compiled; the initial bindings specified in def
forms are installed, however, if and when the flow of control actually reaches the def
form. This explains why the binding
example doesn't work -- it is the compile-time value of *ns*
which counts, while the binding introduced by this binding
form will come into effect at run time.
Finally, if you absolutely insist on using def
forms to create Vars at runtime, the way to do it is with eval
:
(binding [*ns* some-ns]
(eval '(def foo 1)))
;; some-ns/foo comes into existence with a root binding of 1
Note that here def
does occur at top-level and will be immediately executed after compilation.
Upvotes: 5