Search code examples
clojure

*ns* unexpectedly evaluate to 'user' namespace using 'lein run', but not when using 'lein repl'


I am trying to get the namespace associated with the code actually running.

I created a template project using 'lein new app test':

(ns test.core
  (:gen-class))

(defn -main
  [& args]
  (println (ns-name *ns*)))

When using the repl, *ns* evaluates to test.core:

echo "(-main)" | lein repl
nREPL server started on port 37435 on host 127.0.0.1 - nrepl://127.0.0.1:37435
REPL-y 0.4.4, nREPL 0.7.0
Clojure 1.10.1
OpenJDK 64-Bit Server VM 1.8.0_265-b01
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
    Exit: Control+D or (exit) or (quit)
 Results: Stored in vars *1, *2, *3, an exception in *e

test.core=> (-main)
test.core
nil
test.core=> Bye for now!

But when using lein run, I get user namespace:

lein run
user

Why such a behavior ? How can I get the namespace of a piece of code like in the repl ?


Solution

  • A few things to note:

    • *ns* is bound to the namespace wherein the expression is evaluated
    • user is the default namespace
    • when you call (test.core/-main) from the user namespace, *ns* is bound to user, not test.core.

    If you would like to print the namespace in which -main was defined, you can use a top-level expression:

    (ns test.core)
    (def current-ns *ns*)
    (defn -main [& args]
      (println (ns-name current-ns)))
    

    or use var metadata:

    (ns test.core)
    (defn -main [& args]
      (println (ns-name (:ns (meta #'-main)))))