3

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/dd Commented Dec 29, 2014 at 14:51

1 Answer 1

5

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.

Sign up to request clarification or add additional context in comments.

1 Comment

I'll skip the standard comments about the high runtime cost of eval in this answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.