Leiningen, repl, uberjar: Unable to resolve symbol, No such var

325 views Asked by At

While my lein new app project runs merrily inside the Light Table, lein uberjar won't work. Curiously, it behaves exactly like a classic Pascal compiler: it can't resolve references ahead of definitions. Another curiosity: yesterday it worked. I am not aware of fooling with anything sensitive.

Google says that the subj symptoms are quite commonplace; I tried whatever helped other people in the same (?) plight, but to no avail. By the way, usually they blame it on software bugs: "get the latest version of Leiningen and Clojure". I've got 2.5.0 and 1.6.

The project (main file) is here: https://github.com/Tyrn/pcc/blob/master/src/pcc/core.clj As it is, parsed-args can't be resolved inside build-album; if I move the -main function to the top of the file, 'No such var' happens to cli-options inside -main. No amount of fiddling with explicit use of namespaces makes any difference.

Again, inside the Light Table everything runs fine.

1

There are 1 answers

1
xsc On BEST ANSWER

Using def inside of a function is not idiomatic, especially if there is no reason to have it as a global variable. Just pass it as a function parameter:

(let [parsed-args (parse-opts ...)]
  ...
  (build-album parsed-args))

If you really need global state, you can use e.g. a promise (alternatively, an atom):

(defonce parsed-args (promise))
...
(deliver parsed-args (parse-opts ...))

However, Clojure files are read from top to bottom, and yes, functions not having access to bindings introduced later in the file is by design. You can use declare to tell the parser what to expect:

(declare ^:dynamic *parsed-args*)
(defn build-album ...)
(def ^:dynamic *parsed-args* ...)
...
(binding [*parsed-args* (parse-opts ...)]
  (build-album))

TL;DR: If not necessary, avoid global state; if necessary, minimize it.