Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

*file* variable not working

Tags:

clojure

I'm reading in the API docs that the *file* variable should have a value of "the path of the file being evaluated, as a String". However, this feature seems broken in certain cases.

When I execute a file using lein exec, things work as expected:

$ cat test.clj
(println *file*)
$ lein exec test.clj 
/path/to/test.clj

Yet when I run a test that contains a call to (println *file*), NO_SOURCE_PATH is printed instead of the file containing that line.

Why am I seeing this behavior, and how can I reliably access the path and filename of the file being evaluated?

like image 640
Jeff Terrell Ph.D. Avatar asked Oct 02 '12 14:10

Jeff Terrell Ph.D.


1 Answers

*file* is set to the path of the file being compiled, so after your whole program is compiled it is no longer useful to look at the value of *file* (assuming no use of eval).

In your test.clj example, the println is executed while the file is still being compiled. If the reference to *file* is moved into a test or function, it will only be dereferenced at runtime after the value of *file* is no longer useful.

One option is to write a macro that stores the value of *file* when it is expanded, so that the result can be used later. For example, a file example.clj could have:

(defmacro source-file []
  *file*)

(defn foo [x]
  (println "Foo was defined in" (source-file) "and called with" x))

Then from the REPL or anywhere, (foo 42) would print:

Foo was defined in /home/chouser/example.clj and called with 42

Note that it doesn't matter which file source-file is defined in, only where it was expanded, that is the file where foo is defined. This works because it's when foo is compiled that source-file is run, and the return value of source-file which is just a string is then included in the compiled version of foo. The string is then of course available every time foo executes.

If this behaviour is surprising, it may help to consider what would have to happen in order for *file* to have a useful value inside every function at runtime. Its value would have to change for every function call and return, a substantial runtime overhead for a rarely-used feature.

like image 196
Chouser Avatar answered Dec 11 '22 09:12

Chouser