(ns dda.main (:gen-class))
(defn -main [] (prn (ns-name *ns*)))
(ns dda.main (:gen-class))
(def should-exist "Do I exist?")
(defn -main [] (prn (str should-exist \space (ns-name *ns*))))
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
The “trick” I’ve adopted to get around this:
(def my-ns *ns*)
I stick that near the top of any file in which I want to refer to _that_ namespace (as opposed to whatever the _current_ value of *ns* is during evaluation, since it’s dynamic).
Sean Corfield -- (970) FOR-SEAN -- (904) 302-SEAN
An Architect's View -- http://corfield.org/
"If you're not annoying somebody, you're not really alive."
-- Margaret Atwood
--
*ns* is a dynamic var, so it points to the current namespace when your function is running. Most code doesn't switch into a target ns in order to execute functions from it.
*ns* is a dynamic var, so it points to the current namespace when your function is running. Most code doesn't switch into a target ns in order to execute functions from it.I understand that, and I understand most code does not switch into the target ns. But this is not most code, this is the code generated by the gen-class directive to bootstrap your -main method from java. Both lein and clojure.main bootstrap your main method from inside "user", but gen-class does so from inside "clojure.core".So I want to know:1) Why does the generated java class from gen-class has "clojure.core" as its current namespace?
2) Why doesn't the (ns) function inside my namespace change the current namespace?
On Tuesday, June 20, 2017 at 7:43:53 PM UTC-5, Didier wrote:*ns* is a dynamic var, so it points to the current namespace when your function is running. Most code doesn't switch into a target ns in order to execute functions from it.I understand that, and I understand most code does not switch into the target ns. But this is not most code, this is the code generated by the gen-class directive to bootstrap your -main method from java. Both lein and clojure.main bootstrap your main method from inside "user", but gen-class does so from inside "clojure.core".So I want to know:1) Why does the generated java class from gen-class has "clojure.core" as its current namespace?gen-class causes a namespace to be AOT compiled to a class. Leiningen runs the AOT compilation by invoking the compiler. The initial value of *ns* is clojure.core (see RT.java).
During compilation, nothing ever changes this, so that's what gets compiled into the Java class on disk. When you invoke it, this value has been compiled into the class already.
When you invoke -main directly, you are running in the repl. The repl sets the value of *ns* to "user" when it starts, so that's what you see.2) Why doesn't the (ns) function inside my namespace change the current namespace?It does, but only when you run it. The AOT compiled class also creates an init class that will cause the same effects as loading a non-compiled clj file. That file has already expanded `ns` but it will include a call to `in-ns` that will change the current namespace.
However, the compiled class for the -main function already has the value at the time of compilation, so that doesn't matter.
So I get it is simply because the last thing to set ns was RT.
One more question:
So I assume "load" would eval ns in my namespace, setting *ns* to dda.main, then it would run through the file, eval all forms, and finally it would reset *ns* to the previous value. Is that correct, or is there something about loading that's different?
Thanks
Thanks
try { Var.pushThreadBindings( RT.mapUniqueKeys(CURRENT_NS, CURRENT_NS.deref(), WARN_ON_REFLECTION, WARN_ON_REFLECTION.deref() ,RT.UNCHECKED_MATH, RT.UNCHECKED_MATH.deref())); loaded = (loadClassForName(scriptbase.replace('/', '.') + LOADER_SUFFIX) != null); } finally { Var.popThreadBindings(); }
(ns dda.main (:gen-class))
(def should-exist "Do I exist?")
(defn -main []
(in-ns 'other) (ns-name *ns*))
I think I answered myself, looks like it does here:
try { Var.pushThreadBindings( RT.mapUniqueKeys(CURRENT_NS, CURRENT_NS.deref(), WARN_ON_REFLECTION, WARN_ON_REFLECTION.deref() ,RT.UNCHECKED_MATH, RT.UNCHECKED_MATH.deref())); loaded = (loadClassForName(scriptbase.replace('/', '.') + LOADER_SUFFIX) != null); } finally { Var.popThreadBindings(); }
So now I understand, but I wonder if it makes sense. 99% of the time, it won't be an issue, but if you're doing anything with *ns*, you'll run into a situation where if you compile and bootstrap yourself through gen-class or clojure's java API, your code will not behave similar to when you're loaded at runtime or bootsraped through clojure.main or lein.
(ns dda.main(:gen-class))(def should-exist "Do I exist?")(defn -main [](in-ns 'other)(ns-name *ns*))
A bad example, but this code will work through lein, clojure.main, and when loaded from a REPL, but not when started from gen-class or Clojure's java API. Is there a good reason for the discrepancy?
Shouldn't all methods to bootstrap your code start out with an equal initialization scheme?
I would suggest that Clojure's java API (which I assume gen-class uses under the hood)
should also initialize the common bindings and set the namespace to user. That way, all entry point always behave similarly.
1. "compile and bootstrap yourself through gen-class" means: you generate a class and then invoke the main() method of that class
2. "loaded at runtime" means: you (presumably) start the REPL, load a namespace (either from a source file or a class file), then invoke the -main function
(load "dda/main")
(dda.main/-main)
3. "bootstrapped through clojure.main" means: you invoke clojure.main (a compiled program provided with Clojure) with the -m arg specifying a namespace. This will start the Clojure runtime, load the namespace, then invoke the -main function
4. "bootstrapped through lein" means: I assume this is "lein run" with a :main set or "lein run -m" but I think lein supports specifying a namespace or a function in a namespace or a class with a main() method. Depending which of those you're doing, this is like similar to either #1 or #2 and here lein is effectively doing similar work as #3.
5. There is a Clojure Java API (http://clojure.github.io/clojure/javadoc/), but I'm not sure if you are actually referring to this or something else. Doing so would basically mean going through that API to do the same thing as #2.
IFn require = Clojure.var("dda.main", "-main");
require.invoke();
I think if I were to restate your suggestion, I would say that a genclass-compiled main entry point should initialize the Clojure runtime and invoke the code in a binding as if it were being invoked from other Clojure code. I can see some logic in that (although that then also affects #3 and #4 as they go through this code too).
Great breakdown.1. "compile and bootstrap yourself through gen-class" means: you generate a class and then invoke the main() method of that classI'd go further then just calling main. So I mean you generate a class, and every function call from Java using the generated class should be executed as if it were executed through clojure.main, so with the bindings set and inside the user namespace.
2. "loaded at runtime" means: you (presumably) start the REPL, load a namespace (either from a source file or a class file), then invoke the -main functionCorrect. It's the case of a non AOT compiled namespace being loaded from one of the many (load) functions of Clojure. Such as:
(load "dda/main")
(dda.main/-main)3. "bootstrapped through clojure.main" means: you invoke clojure.main (a compiled program provided with Clojure) with the -m arg specifying a namespace. This will start the Clojure runtime, load the namespace, then invoke the -main functionCorrect.4. "bootstrapped through lein" means: I assume this is "lein run" with a :main set or "lein run -m" but I think lein supports specifying a namespace or a function in a namespace or a class with a main() method. Depending which of those you're doing, this is like similar to either #1 or #2 and here lein is effectively doing similar work as #3.Correct, yes internally lein delegates to clojure.main I believe.
5. There is a Clojure Java API (http://clojure.github.io/clojure/javadoc/), but I'm not sure if you are actually referring to this or something else. Doing so would basically mean going through that API to do the same thing as #2.I am talking about that API. I believe it uses RT under the hood, and ends up doing the same thing that #1 does. So in my test, if you did:
IFn require = Clojure.var("dda.main", "-main");
require.invoke();
This will run inside "clojure.core", and will not have any of the default bindings set available.I think if I were to restate your suggestion, I would say that a genclass-compiled main entry point should initialize the Clojure runtime and invoke the code in a binding as if it were being invoked from other Clojure code. I can see some logic in that (although that then also affects #3 and #4 as they go through this code too).Ya, arguably, I wonder why the clojure runtime doesn't initialize the bindings and sets the namespace to 'user before delegating execution back to user code.
If it did, then every invocation of Clojure from Java would always be bootstrapped in a similar way, and run under an equal context. Clojure.main wouldn't need to do it anymore.But there might be a good reason for not doing that inside the clojure runtime. In which case, it still leaves open the question of should clojure invocations through a generated class, and invocations from the Clojure API mimic the bootstrapping of clojure.main?
At the Repl it’s best to use in-ns, in which case the new namespace will contain mappings only for the classnames in java.lang. In order to access the names from theclojure.core
namespace you must execute (clojure.core/refer 'clojure.core). Theuser
namespace at the Repl has already done this.
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.