Reputation: 1038
I'm unclear why in the following code snippet, foo is being defined in the "user" namespace, and not the one I've bound to *ns* in the binding closure. Can someone explain what I'm missing?
$ clj Clojure 1.4.0 user=> (let [nspace (create-ns (gensym "sandbox"))] (binding [*ns* nspace] (print (ns-name *ns*)) (def foo 6))) sandbox3#'user/foo user=> foo 6 user=> (in-ns 'sandbox3) # sandbox3=> foo CompilerException java.lang.RuntimeException: Unable to resolve symbol: foo in this context, compiling:(NO_SOURCE_PATH:0) sandbox3=> (def bar 7) #'sandbox3/bar sandbox3=> bar 7 sandbox3/user=> (in-ns 'user) # user=> foo 6 user=> bar CompilerException java.lang.RuntimeException: Unable to resolve symbol: bar in this context, compiling:(NO_SOURCE_PATH:0)
Upvotes: 1
Views: 303
Reputation: 32675
You'll need to use eval:
(let [nspace (create-ns (gensym "sandbox"))]
(binding [*ns* nspace]
(print (ns-name *ns*))
(eval '(def foo 6))))
eval
pays attention to *ns*
, but most of Clojure does not.
EDIT: Yes, I just suggested that a person use eval :p
For context, I've been corresponding with op and he doesn't want a real sandbox as he trusts the code going into his system, he simply needed a way to evaluate inputted code inside of different namespaces!
So, if you're a newbie with this question and you're not sethwm, please refer to Marczyk's answer. This solution is very specific to the OP's use case and not a generally good way to do much of anything.
Upvotes: 3
Reputation: 84379
The namespace in which def
will create a Var is determined at compile time. The binding is not in effect then (binding
introduces runtime bindings).
def
should only be used at top level or inside something like a top-level let
form. The further one drifts away from a simple top-level def
, the greater the care that one should exercise. For example binding
is certainly similar to a top-level let
in many ways and the value part of a def
expression will be evaluated with the expected thread-local bindings in place:
user=> (let [nspace (create-ns (gensym "foo"))]
(binding [*ns* nspace]
(def foo *ns*)))
#'user/foo
user=> foo
#<Namespace foo3>
The fashion in which the Var is created in the first place is, however, completely unaffected by the runtime state when execution reaches the def
form.
To create Vars dynamically, use intern
-- it's a regular function with completely predictable behaviour.
Upvotes: 6