I don't understand why the following code produces a reflection warning:
(set! *warn-on-reflection* true)
(defmacro my-macro [k] `(.length ~(with-meta k {:tag String})))
(defn my-fun1 [k] (my-macro k))
;; Reflection warning, /tmp/form-init2370243866132870536.clj:1:18 - reference to field length can't be resolved.
Using macroexpand-1
shows that the generated code does have the typehint, and if I write the same code manually without using a macro, there is no reflection warning:
(set! *print-meta* true)
(macroexpand-1 '(my-macro k))
;; (.length ^java.lang.String k)
(defn my-fun2 [k] (.length ^String k))
;; All good, no reflection warning
Benchmarking the function shows that the warning is not just a red herring, the reflection actually occurs at runtime:
(time (reduce + (map my-fun1 (repeat 1000000 "test"))))
;; "Elapsed time: 3080.252792 msecs"
(time (reduce + (map my-fun2 (repeat 1000000 "test"))))
;; "Elapsed time: 275.204877 msecs"
The tag should be a Symbol, not a Class. So the following code works:
(defmacro my-macro [k] `(.length ~(with-meta k {:tag `String})))
This is actually stated in the documentation of special forms:
:tag
a symbol naming a class or a Class object that indicates the Java type of the object in the var, or its return value if the object is a fn.
The fact that macroexpand-1
shows a type hint that is invalid but looks exactly like the correct one is quite misleading :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With