Simple as the headline suggest:
Why do I have to
(require 'clojure.edn)
in order to use e.g.:
(clojure.edn/read-string "9")
And why can I immediately invoke:
(clojure.string/join (range 4) "-")
Clojure programs start at the top of the "main" namespace (often project-name.core) and evaluate each form from top to bottom. This happens when the program starts, and before any "main" functions are invoked.
When a require expression is evaluated it jumps over to that namespace and does the same thing there. If requires are encountered there it recurses down branches of those namespaces, recursively loading each namespace as required.
So If you don't explicitly state that your namespace requires another namespace, then you are at the mercy of the order that other namspaces you require load their dependencies. Sometimes it will work, and sometimes unrelated changes to the evaulation order of your distant dependencies will break your code.
So please, please, ... declare your own requirements!
in the repl (just starting clojure) I have the following ns loaded by default
user=> (pprint (map #(.getName %) (all-ns)))
(clojure.edn
clojure.core.server
clojure.java.io
clojure.java.shell
clojure.core.protocols
clojure.string
clojure.java.browse
clojure.pprint
clojure.uuid
clojure.core
clojure.main
user
clojure.java.javadoc
clojure.repl
clojure.walk
clojure.instant)
in whichever namespace you are in, clojure.edn seems not to be loaded
Related
I came across this problem after creating a new namespace.
Here is the code:
(create-ns 'my-new-ns)
=> #object[clojure.lang.Namespace 0x7c7c8359 "my-new-ns"]
(in-ns 'my-new-ns)
=> #object[clojure.lang.Namespace 0x7c7c8359 "my-new-ns"]
(reduce + [1 2 3])
CompilerException java.lang.RuntimeException: Unable to resolve symbol: reduce in this context, compiling:(/private/var/folders/pg/bynypsm12nx1s4gzm56mwtcr0000gn/T/form-init1425759900088902804.clj:1:1)
As you can see reduce function is not defined in my-new-ns namespace.
I should be able to create new namespaces so What would be the best solution for this problem?
P.S: Also, I'm trying to create those namespaces for my users so they will be able to do whatever they want in their namespaces(the idea is like a container) and creating isolation between namespaces.
clojure.core functions are not special in their need to be referred to make them available for unqualified use. The ns macro does several things:
creates the namespace - create-ns
changes the current namespace to that namespace - in-ns
automatically refers all of the clojure.core vars into the new namespace - refer-clojure
You can always use the qualified form of the core function (unqualified is just less typing), so when you get in this situation, this simple call will get you right again:
(clojure.core/refer-clojure)
Instead of creating namespace manually and then switching to it, I'd recommend using ns macro. According to the doc:
Sets *ns* to the namespace named by name (unevaluated), creating it if needed.
Also it will load all public vars from clojure.core to newly created namespace.
So, basically this
> (create-ns 'my-new-ns)
> (in-ns 'my-new-ns)
> (clojure.core/refer 'clojure.core)
is equal to this
> (ns my-new-ns)
Update:
Answering your question: symbols from standard library are not referred in newly created namespace, that's why you cannot access them without qualifier:
> (create-ns 'x)
> (in-ns 'x)
> reduce ;; throws "Unable to resolve symbol"
> clojure.core/reduce ;; works fine
You need to refer those symbols manually by calling (clojure.core/refer 'clojure.core).
Your new namespace needs to use the "standard" namespaces to be able to resolve names in them. The documentation indicates that this would be java.lang, clojure.lang.Compiler and clojure.core.
I guess you are supposed to use
(ns my-new-ns)
instead. create-ns is a low-level facility.
I've set up small project:
project.clj:
(defproject testing-compilation "0.1.0-SNAPSHOT"
:dependencies [[org.clojure/clojure "1.8.0"]]
;; this is important!
:aot :all)
src/core.clj
(ns testing-compilation.core)
(def x (do
(println "Print during compilation?")
1))
Then when I do lein compile in project directory I'm seeing output from a print:
$ lein compile
Compiling testing-compilation.core
Print during compilation?
My question is: why clojure evaluates top level forms during AOT compilation? Shouldn't they be evaluated at program startup?
For reference, Common Lisp doesn't evaluate forms by default and provides ability to tune this behaviour. Anything similar in Clojure? If nothing, does Clojure documentation explicitly state such behaviour?
UPD: Forms are evaluated at startup as well.
After specifying a main namespace and writing main function that prints Hello, world!, I did this:
$ lein uberjar
Compiling testing-compilation.core
Print during compilation?
Created testing-compilation-0.1.0-SNAPSHOT.jar
Created testing-compilation-0.1.0-SNAPSHOT-standalone.jar
$ java -jar target/testing-compilation-0.1.0-SNAPSHOT-standalone.jar
Print during compilation?
Hello world!
The first part of the AOT process is to find the file containing the main namespace and load it by evaluating every expression from top to bottom.
Some of these expressions will be require expressions that will have the effect of loading other namespaces, which recursively load yet more namespaces.
Other will be defn expressions that will have the effect of firing up the compiler and producing class files. One class file is produced for each function.
Other expressions may do some calculation and then do things that produce class files, so it's important to give them a chance to run. Here's a made up example:
user> (let [precomputed-value (reduce + (range 5))]
(defn funfunfun [x]
(+ x precomputed-value)))
#'user/funfunfun
user> (funfunfun 4)
14
It is possible to design a lisp that would not evaluate top level forms at start or, as you mention, make it optional. In the case of Clojure it was decided to keep a single evaluation strategy across both AOT and "non AOT" loading so programs always run the same regardless of how they are compiled. These are personal design choices made by others so I can't speak to their motivations here.
I'm trying to understand "Lieningen" behaviour when creating an uberjar. Following is the minimal example which reproduces the behaviour:
(ns my-stuff.core
(:gen-class))
(def some-var (throw (Exception. "boom!")))
(defn -main [& args]
(println some-var))
When this is executed with lein run it clearly fails with an Exception. However, I don't understand why executing lein uberjar also fails with an Exception from variable definition? Why executing lein uberjar attempts to evaluate the variable value? Is this speecific to uberjar task or am I missing something more substantial about Clojure or Leiningen?
In order to compile your namespace for the uberjar (if you have AOT turned on), the clojure compiler must load your namespace. This will always invoke all top-level side effects.
The best way to handle this is to never have side effects in top level code (whether inside or outside a def form), and have initialization functions to realize any start-up side effects needed.
A workaround can be to make a small namespace that uses introspection to load the rest of your code at runtime but not while compiling - using a function like this:
(defn -main
[]
(require 'my.primary.ns)
((resolve 'my.primary.ns/start)))
if that namespace is compiled, the jvm can find -main and run it, despite none of your other code being compiled. The runtime require will cause the Clojure compiler to load the rest of your code at runtime only, and resolve is needed so that -main will compile cleanly - it returns the var referenced, which then invokes your function when called.
I'm familiar with packages from e.g. Java and Lisp, but what I'm seeing in other people's code is some apparent idioms like calling the entry point '-main' and using a backtick for the namespace name in (in-ns `foo), that kind of thing. I don't see these spelled out anywhere in docs or tutorials. Is there some resource which explains such conventions around structuring programs?
Edit:
I think I must have picked up the backtick thing from this answer: Splitting a Clojure namespace over multiple files, which I stumbled across while trying to make sense of (defn -main ...). Given the author, I took it as best practice. However, now that I poke around in the Clojure sources he cites, I see that only the regular quote is used. I guess most likely it's a typo.
(Narrowed the scope of the question title accordingly)
The default for gen-class is to use - as the prefix for method names of that class. Which is why -main is the default entry point for java -cp clojure.jar yourclass
Backticks qualify their argument with the current namespace, so (in-ns `foo) is the same as (in-ns 'current-namespace/foo) and I don't think that's particularly idiomatic. The idiomatic way is to put each namespace in its own file with (ns ...) at the top, and use or require them as needed.
Is there an idiomatic way to get available namespaces that can be used?
(all-ns) returns only already used namespaces. (Package/getPackages) returns all Java packages available for import, but only those Clojure namespaces that are already used.
Then I stumbled upon this post, but it uses some classpath magic.
So I want to get something like ('clojure.core 'clojure.set ... 'clojure.contrib.accumulators 'clojure.contrib.condition ...) if I have the clojure.jar and contrib.jar on my classpath, but I haven't used anything yet.
You will need to do "classpath magic". Since there is no kind of registry, you have to walk the classpath and look in every clojure source file to determine what namespaces are available. (In case the files are not AOT compiled. Otherwise you'll need a different heuristic.)
I think the function used in the linked post is the best way to go: clojure.contrib.find-namespaces/find-namespaces-on-classpath.
Deprecated since Clojure 1.3.0; use now clojure.tools.namespace.find/find-namespaces and clojure.java.classpath/classpath from http://github.com/clojure/java.classpath
I have found bultitude to be a great tool for doing this.
Example:
user=> (require '[bultitude.core :as b])
nil
user=> (take 10 (b/namespaces-on-classpath))
(bultitude.core-test bultitude.core clojure.data clojure.string clojure.test clojure.xml clojure.inspector clojure.repl clojure.set clojure.test.junit)
user=> (b/namespaces-on-classpath :prefix "bultitude")
(bultitude.core-test bultitude.core)