Welcome! Please see the About page for a little more info on how this works.

0 votes
in Errors by
When *compile-path* is not set to a String but to a java.io.File (that's what boot-clj does at the moment). You get a Cast exception in the compiler when trying to use it from the boot repl. Common wisdom seems to be to not compile from the repl, people say don't use gen-class. I find this unfortunate for when you do want to use gen-class and iterate quickly.

I haven't tested all older versions for this issue, but git blame shows that the code that should help here wasn't changed for 10 years:
https://github.com/clojure/clojure/blame/master/src/clj/clojure/core.clj#L6073
https://github.com/clojure/clojure/blame/master/src/jvm/clojure/lang/Compiler.java#L7643

My workaround now is:


(defn compile-safely [ns-name]
  (let [compile-path-class *compile-path*
        corrected-path (cond
                         (instance? java.io.File compile-path-class) (.getAbsolutePath *compile-path*)
                         (instance? String compile-path-class)       *compile-path*
                         :else
                         (throw (ex-info "Unsupported class" {:class (class compile-path-class)})))]
    (binding [*compile-path* corrected-path]
      (compile ns-name))))


I suggest to put the type check in the 'clojure.core/compile function.

5 Answers

0 votes
by

Comment made by: jeroen

Reference to common wisdom https://clojurians-log.clojureverse.org/clojure/2017-06-05/1496700773.347309

0 votes
by

Comment made by: jeroen

The following works in boot-clj (because of classpath issues not in Leiningen and clj cli): https://gist.github.com/jeroenvandijk/8187413d24433545eeb9579538a903f7#file-repl_compile-clj-L39-L52

0 votes
by

Comment made by: alexmiller

Can you provide a reproducible example?

Seems like ClassCastException is pretty accurate for having a class of the wrong type.

0 votes
by
_Comment made by: jeroen_

I've tried to make the example as simple as possible. You are right that the ClassCastException is perfectly accurate, but you realise this only after you have figured out it's about *compile-path*. This bug report is mostly about managing expectations (of the clojure user).



clj -A:new app example.error
cd example.error
clj

 ;; clj has the *compile-path* set correctly to a string (although not in the classpath)
 *compile-path* ;=> "classes"
 (let [f (clojure.java.io/file "classes/foo.clj")]
   (clojure.java.io/make-parents f)
   (spit f "(ns foo) (gen-class :name my.new.Class)")
   (compile 'foo)
   (clojure.java.shell/sh "ls" "classes"))
 ; success, although you still cannot load the class
 ; #=> {:exit 0, :out  "clojure\nfoo$fn__134.class\nfoo$fn__166.class\nfoo$fn__174.class\nfoo$loading__6549__auto____132.class\nfoo$loading__6549__auto____164.class\nfoo$loading__6549__auto____172.class\nfoo.clj\nfoo__init.class\n", :err ""}
 

 ;; From a boot project:
 ;; boot.user=> *compile-path*
 ;; #object[java.io.File 0x5266b1a "/var/folders/ck/9zqvs0zx5vsf2bc7rvv1pwc40000gn/T/boot-repl8170014881711480931"]
 ;; This can be reproduced in the clj repl:
 (binding [*compile-path* (clojure.java.io/file "classes")]
   (compile 'foo)
   )

 Syntax error compiling fn* at (foo.clj:1:1).
 Cause: java.io.File cannot be cast to java.lang.String
 
 
0 votes
by
Reference: https://clojure.atlassian.net/browse/CLJ-2412 (reported by jeroen)
...