Boolean return type-hint confusing the compiler

Description

Saving the below snippet and running it like

java -jar clojure-1.6.0.jar snippet.clj

Produces

$ java -jar clojure-1.6.0.jar snippet.clj Exception in thread "main" java.lang.IllegalArgumentException: Unable to resolve classname: clojure.core$boolean@1356d4d4, compiling:(/Users/kamstrup/tmp/snippet.clj:15:1) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6651) at clojure.lang.Compiler.analyze(Compiler.java:6445) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6632) at clojure.lang.Compiler.analyze(Compiler.java:6445) at clojure.lang.Compiler.access$100(Compiler.java:38) at clojure.lang.Compiler$DefExpr$Parser.parse(Compiler.java:538) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6644) at clojure.lang.Compiler.analyze(Compiler.java:6445) at clojure.lang.Compiler.analyze(Compiler.java:6406) at clojure.lang.Compiler.eval(Compiler.java:6707) at clojure.lang.Compiler.load(Compiler.java:7130) at clojure.lang.Compiler.loadFile(Compiler.java:7086) at clojure.main$load_script.invoke(main.clj:274) at clojure.main$script_opt.invoke(main.clj:336) at clojure.main$main.doInvoke(main.clj:420) at clojure.lang.RestFn.invoke(RestFn.java:408) at clojure.lang.Var.invoke(Var.java:379) at clojure.lang.AFn.applyToHelper(AFn.java:154) at clojure.lang.Var.applyTo(Var.java:700) at clojure.main.main(main.java:37) Caused by: java.lang.IllegalArgumentException: Unable to resolve classname: clojure.core$boolean@1356d4d4 at clojure.lang.Compiler$HostExpr.tagToClass(Compiler.java:1069) at clojure.lang.Compiler$InvokeExpr.getJavaClass(Compiler.java:3659) at clojure.lang.Compiler$LocalBinding.hasJavaClass(Compiler.java:5657) at clojure.lang.Compiler$LocalBindingExpr.hasJavaClass(Compiler.java:5751) at clojure.lang.Compiler.maybePrimitiveType(Compiler.java:1283) at clojure.lang.Compiler$IfExpr.doEmit(Compiler.java:2631) at clojure.lang.Compiler$IfExpr.emit(Compiler.java:2613) at clojure.lang.Compiler$BodyExpr.emit(Compiler.java:5826) at clojure.lang.Compiler$LetExpr.doEmit(Compiler.java:6180) at clojure.lang.Compiler$LetExpr.emit(Compiler.java:6133) at clojure.lang.Compiler$BodyExpr.emit(Compiler.java:5826) at clojure.lang.Compiler$FnMethod.doEmit(Compiler.java:5374) at clojure.lang.Compiler$FnMethod.emit(Compiler.java:5232) at clojure.lang.Compiler$FnExpr.emitMethods(Compiler.java:3771) at clojure.lang.Compiler$ObjExpr.compile(Compiler.java:4410) at clojure.lang.Compiler$FnExpr.parse(Compiler.java:3904) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6642) ... 19 more

The snippet:

snippet.clj

;; Bug in the Clojure compiler (1.6.0): If we annotate the return here with ^boolean we get: ;; 'IllegalArgumentException: Unable to resolve classname: clojure.core$boolean' from the compiler. ;; Removing it, everything is as expected (defn ^boolean foo-bar? [node] (= node "foo-bar")) ;; Check it out, we can have ^boolean here, but not on foo-bar? !! :-) (defn ^boolean bar-foo? [node] (= node "bar-foo")) ;; Instead of removing the ^boolean return on foo-bar? we can also remove this function ;; to have all work as expected (defn ^boolean interesting? [node] (or (foo-bar? node) (bar-foo? node))) (println "Foo-Bar?" (foo-bar? "baz"))

Environment

OSX, Clojure 1.6.0

Activity

Show:

Alex MillerJanuary 19, 2022 at 9:21 PM

Andy FingerhutMarch 12, 2015 at 2:36 PM

Mikkel: If the type tags are Java classes, not primitives, then ^Classname is a correct type tag. If you use Eastwood, it can warn about these incorrect type tags, and has some documentation on what works and what does not here: https://github.com/jonase/eastwood#wrong-tag

Also here: https://github.com/jonase/eastwood#unused-meta-on-macro

importMarch 12, 2015 at 12:36 PM

Comment made by: kamstrup

Thanks for clarifying Nicola, you are indeed correct.

Putting return type annotations before the method name seems to be common practice in a lot of Clojure code I've read online. Perpetuated by some online tutorials, and the clojure.org docs them selves (fx.

(defn ^:private ^String my-fn ...)

is found in http://clojure.org/cheatsheet)

Nicola MomettoMarch 12, 2015 at 12:01 PM

Metadata on def's symbol is evaluated as per the doc (http://clojure.org/special_forms), evaluating `boolean` results in the clojure.core/boolean function which is not a valid type hint.

As a rule of thumb, attach the return tag in the argvec rather than on the def symbol, in this case you should write

(defn foo-bar? ^boolean [node] (= node "foo-bar"))

I understand why the fact that

(defn ^boolean foo [] true)

and

(defn foo ^boolean [] true)

behave differently and the fact that the compiler will throw iff the type hint is used rather than throwing at the function definition time is confusing (and I've complained about this and the lack of documentation/specification regarding type hints for a while) but this is not a bug

importMarch 12, 2015 at 11:25 AM

Comment made by: kamstrup

Typo in comment 2 in the snippet: s/xtc-scenario?/foo-bar?/

Duplicate

Details

Assignee

Reporter

Labels

Priority

Created March 12, 2015 at 11:15 AM
Updated January 19, 2022 at 9:21 PM
Resolved January 19, 2022 at 9:21 PM

Flag notifications