3
votes

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)
1
I do not suggest using this, but this would work: (do (in-ns 'some-a-ns) (def dd 100)) - defines dd as some-a-ns/ddPetr Gladkikh

1 Answers

5
votes

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.