Code execution in another Clojure namespace, why is eval required?

I look at the implementation of the old c-ns tab macro:

(defmacro with-ns "Evaluates body in another namespace. ns is either a namespace object or a symbol. This makes it possible to define functions in namespaces other than the current one." [ns & body] `(binding [*ns* (the-ns ~ns)] ~@ (map (fn [form] `(eval '~form)) body))) 

What I do not understand is the need for an examination of the body. In other words, why this does not work when I want to access elements in the target namespace inside the body without eval (example below).

 user=> (defmacro wns [ns & body] `(binding [*ns* (the-ns ~ns)] ~@body )) #'user/wns user=> (create-ns 'boofar) #<Namespace boofar> user=> (in-ns 'boofar) #<Namespace boofar> boofar=> (clojure.core/refer-clojure) nil boofar=> (defn xx [ab] (str ab)) #'boofar/xx boofar=> (xx 5 6) "56" boofar=> (in-ns 'user) #<Namespace user> user=> (with-ns 'boofar (println *ns*) (xx 5 6)) #<Namespace boofar> "56" user=> (wns 'boofar (println *ns*) (xx 5 6)) CompilerException java.lang.RuntimeException: Unable to resolve symbol: xx in this context, compiling:(blardy/blardy/form-init3758076021118964250.clj:1:29) user=> (wns 'boofar (println *ns*)) #<Namespace boofar> nil 

I'm fine with that. I really do not mind, but I would like to understand what is happening here. xx clearly exists in the boofar namespace, and clicking on ns binding should put me there, but I cannot name it directly, however I can name something in clojure.core that was passed. In case you are interested, I tried rewriting the macro to use in-ns with the appropriate try / finally, and the result will be the same.

Thanks!

change

Added macro example using in-ns . The results are the same as without.

 user=> (defmacro wins [ns & body] `(let [orig-ns# (ns-name *ns*)] (try (in-ns ~ns) ~@body (finally (in-ns orig-ns#))))) 

Advanced Macro ...

 user=> (pprint (macroexpand-all '(wins 'boofar2 (xx 7 8)))) (let* [orig-ns__4137__auto__ (clojure.core/ns-name clojure.core/*ns*)] (try (clojure.core/in-ns 'boofar2) (xx 7 8) (finally (clojure.core/in-ns orig-ns__4137__auto__)))) 

Using it ...

 user=> (defn xx [ab] (str "user/xx [" a " " b "]")) user=> (in-ns 'boofar2) boofar2=> (defn xx [ab] (str "boofar2/xx [" a " " b "]")) boofar2=> (in-ns 'user) user=> (wins 'boofar2 (xx 7 8)) "user/xx [7 8]" 
+6
source share
1 answer

Configuring ns with bindings doesn't quite work this way, so the document for namespaces includes this warning :

 "The current namespace, *ns* can and should be set only with a call to in-ns or the ns macro, both of which create the namespace if it doesn't exist." 

In your example, the xx character is resolved in the namespace user instead of the namespace to which * ns * is bound:

 user> (defn xx [ab] "I'm the xx from ns user") #'user/xx user> (wns 'boofar (println *ns*) (xx 5 6)) #<Namespace boofar> "I'm the xx from ns user" 
+7
source

All Articles