tags:

views:

562

answers:

5

When I evaluate (use 'hello) to load hello.clj, the REPL complains with the following error:

java.io.FileNotFoundException: Could not locate hello__init.class or hello.clj on classpath:  (NO_SOURCE_FILE:0)

I'm invoking the REPL like this:

java -cp "/Library/Java/Extensions/servlet-api-2.5-20081211.jar:... lots of jarfiles ...:/Library/Java/Extensions/clojure-contrib.jar:/Library/Java/Extensions/clojure-1.0.0.jar:./classes/:." jline.ConsoleRunner clojure.lang.Repl

Reading around, this looks like the file isn't being found in the PWD, but I've added . to the path with no success :-(.

Running with Java 1.6 on OS X 10.6.

I'm sure I'm being an idiot, can someone hit me with a LART?

EDIT: I also tried the ClojureX distro, and got the same results.

+2  A: 

when I'm working from the repl and want to load files i find i have to call something like this first:

(add-classpath "file:///home/arthur/.../src/")
(add-classpath "file:///home/arthur/.../build/")

before the repl can find them on the classpath. I put these in a file that is not included in the jar file along with a statement that reloads everything from the other files. When I build a jar file i find I don't need to do this.

Arthur Ulfeldt
Please don't do that! add-classpath is *only* for experimenting. The Right Way for a regular setup is as the OP did: set up the classpath on startup of the JVM. Adding paths with add-classpath is regularly broken and will come back to haunt you. This is just the way the JVM is designed.
kotarak
When I use add-classpath as suggested, it does at least work well enough to find hello.clj and load it. It seems add-classpath is doing something that the env CLASSPATH variable is not.
Ben Godfrey
Kotarak can you point to any examples of how exactly add-classpath is broken and how the dangers can manifest? Thanks
Wojciech Kaczmarek
+2  A: 

Does hello.clj contain a (ns some-namespace) statement? If so, then same_namespace is appended to the each element of the CLASSPATH before looking for hello.clj

I didn't know that, thanks!I have a couple of test files. One defines a namespace, the other does not. Neither work unfortunately. I moved the namespace-defining test to a subdir of the classpath, but still no luck.
Ben Godfrey
I should have said the parent elements of 'some-namespace'. That is a file with (ns some.namespace) should be named 'namespace.clj' in a subdirectory 'some'.
+1  A: 

I've defined an alias (in .bash_profile) for loading the REPL:

alias clojure='CLASSPATH=$HOME/git/clojure/clojure.jar:$HOME/git/clojure-contrib/clojure-contrib.jar:.:classes rlwrap java clojure.lang.Repl'
Michiel de Mare
+3  A: 

If hello.clj is in $DIR and $DIR is on your classpath, then hello.clj needs to start with (ns hello). If it's in $DIR/$SUBDIR and $DIR is on your classpath, then hello.clj needs to start with (ns $SUBDIR.hello). Generally, your filename structure and the ns name structure must match, with filename separator replaced by . in ns name and any _s in the filename corresponding to -s in the ns name. The name of the actual file needs to be the final component (possibly the only component, if the file's containing dir is on the classpath) of the namespace name.

EDIT:

An extended example. No information beyond what I've written above, so please skip over it if that was enough for you; however I know that getting CP right was quite painful for me in the beginning, so I decided I'd write this out in a step by step fashion so that someone, somewhere might perhaps be spared that particular `learning experience' ;-).

Say this is your namespace definition:

;;; in file "hello.clj"
(ns hello)

(defn hello []
  (println "Hello!"))

Then if you put the directory containing hello.clj on your classpath, you're good to go and a (use 'hello) at the REPL should do what you want.

If, on the other hand, you do this:

;;; in file "hello.clj"
(ns my-namespace)
;;; ...

or this:

;;; in file "my-filename.clj"
(ns hello)
;;; ...

-- that is, if you introduce a mismatch between the name of the file and the name of the namespace, Clojure won't be able to find your namespace.

Also, if you put hello.clj in /path/to/code, but what you have on your classpath is actually /path/to, i.e. the parent directory of /path/to/code, you need to do this:

;;; in file "/path/to/code/hello.clj"
(ns code.hello)
;;; ...

Then you'll be able to (use 'code.hello).

Finally, if you call your file my_namespace.clj, you need to call your ns my-namespace (and the other way around). _s in namespace names and -s in filenames should not be used.

Michał Marczyk
Thanks very much for going into so much detail here. I ran through all your examples and still had no luck. I think my system must be broken somehow.
Ben Godfrey
Sure. But, um... it still doesn't work!? At this point I'm inclined to share your suspicions. I'll post any follow-up questions as comments to the question, if I can think of any... Good luck!
Michał Marczyk
I'm surprised that Clojure is taking Java's double-encoding of syntactic package declaration and physical directory path one step further, now requiring the file name itself to also be part of the namespace -- even though there need not be any classes generated on behalf of a particular file. In CL, packages are divorced from source files. In Clojure, are namespaces supposed to be divorceable from files? Should a namespace be able to span multiple contributing source files? The Clojure documentation is mute on this point.
seh
Michał Marczyk
+1  A: 

I have the following lines on my .emacs:

(setq swank-clojure-jar-path "~/src/clojure/clojure.jar"
      swank-clojure-extra-classpaths (append 
                      (directory-files "~/src/compojure/deps" t ".jar$")
                      (list
                       "~/src/swank-clojure/src/main/clojure"
                       "~/src/clojure-contrib/clojure-contrib.jar"
                       "~/src/clj/.")))

I load the programe snake.clj which is at ~/src/clj and eval it (C-x h which selects the entire buffer and then C-c C-c to compile). The programs creates a namespace by name snake. Now, from emacs/slime, I do

(use 'snake)

That's it.Now invoke any function defined in the namespace.

Your problem may be that the directory on which you have hello.clj may not be on your classpath. Also make sure you name the namespace properly. If inside hello.clj, you named your name space as hello, then you do (use 'hello).

Ramakrishnan Muthukrishnan