1

I am new to Clojure and am just trying to build some sample apps to get used to the syntax. I noticed the following order dependency behaviour.

I created a project called timex to calculate the time in weeks between two dates. I am using the clj-time functions for the date difference calculations.

If my core.clj looks as follows:

 (ns timex.core
  (:gen-class))
 (defn -main
  "Calculate weeks between dates."
  [& args]
  dp
   )
 (require '[clj-time.core :as t])
 (def d2 (t/date-time 1989 01 07))
 (def dw (t/in-weeks (t/interval d2 (t/now))))
 (def dp (str "The number of weeks between Jan 7, 1989 and now is " dw "!"))

**

If I run lein repl I get the following error: #CompilerException java.lang.RuntimeException: Unable to resolve symbol: dp in this context, compiling:(timex/core.clj:4:1)

But if I re-order the lines in the file and put the def's and the require statement before the main as such

(ns timex.core
  (:gen-class))
 (require '[clj-time.core :as t])
 (def d2 (t/date-time 1989 01 07))
 (def dw (t/in-weeks (t/interval d2 (t/now))))
 (def dp (str "The number of weeks between Jan 7, 1989 and now is " dw "!"))
 (defn -main
  "Calculate weeks between dates."
  [& args]
  dp
   )

**

Then when I run lein repl and the invoke the (-main) function, I get:

timex.core=> (-main)

"The number of weeks between Jan 7, 1989 and now is 1341!"

Is this apparent order-dependency normal or am I doing something wrong? If the latter, then I would appreciate any advice or documentation I should review. Thanks.

1 Answer 1

3

The unit of compilation in Clojure is the s-expression as opposed to a whole file like many other languages. When you load a file that file file is evaluated from top to bottom in a single pass. vars (what is created by calls to def) must be created above where they are used, or you can use declare if you need mutual recursion though this is rare.

It's worth spending some time getting used to the difference between compiling a file in the traditional sense, and loading a file in the lisp sense because it is fundamental to the macro system and many other aspects of the language. When you require a file from a namespace, or call load-file from the repl the clojure compiler is invoked and repeatedly reads, macro-expands, then evaluates each from in the file starting at the top. The first line tels it what namespace to define things in which is why the ns expression comes first. Then further forms define things in that namespace. If you then load the file again it does nothing more than read the file from the top all over again. It does not clear the namespace or any other magic, so if you evaluate the file, then change the order and evaluate it again it can continue to work because the required functions are already defined in the namespace (as stored in memeory) when the second pass is run. When getting used to this it helps to run lein check often to make sure things are well ordered.

PS: the vast majority of the time the call to require goes in the ns form at the top of the file.

Sign up to request clarification or add additional context in comments.

1 Comment

There is an article The system paradigm discussing the design ideas related to the compilation unit.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.