The main use I've had for with-meta is in macros, to attach e.g. type hints to a symbol that's going into the macro expansion. There, the ^ reader macro adds the metadata too early rather than with-meta adding it too late: ^ hints some symbol in the macro body and the compiler will apply the type hint in compiling the macro itself, rather than in compiling whatever the macro outputs as its expansion.
So, ^String x ......... x in ordinary functions, x ........ ~(with-meta x {:tag 'String}) in macros. To recap, hinting x in the macro is useless, because x, a variable in the macro itself, isn't what you want to hint; some symbol in the output is what you want to hint. Another variation is ~(with-meta (gensym) {:tag 'SomeClass}). You might also want to fully qualify the classname when it's not in java.lang; otherwise the *source files where the macro is called* will have to :import the appropriate package. So, ~(with-meta x {:tag 'com.something.somepackage.SomeClass}). Remember, the macro effectively just replaces its own call with its own output, so if you have (ns foo :import (java.util.concurrent ConcurrentHashMap)) (defn bar [x] (my-macro [a x] (do-something-with a))) and my-macro type-hints something as String, you effectively are compiling something like: (ns foo :import (java.util.concurrent ConcurrentHashMap)) (defn bar [x] (let [^String a x] (if (macro-supplied-condition-on-a) (do-something-with a) (default-macro-supplied-action))))) and String resolves because it's in java.lang. If the type hint is ConcurrentHashMap: (ns foo :import (java.util.concurrent ConcurrentHashMap)) (defn bar [x] (let [^ConcurrentHashMap a x] (if (macro-supplied-condition-on-a) (do-something-with a) (default-macro-supplied-action))))) and ConcurrentHashMap resolves because the file that *uses* the macro imports it. If the type hint is JPanel: (ns foo :import (java.util.concurrent ConcurrentHashMap)) (defn bar [x] (let [^JPanel a x] (if (macro-supplied-condition-on-a) (do-something-with a) (default-macro-supplied-action))))) #<CompilerException java.lang.IllegalArgumentException: Unable to resolve classname: JPanel (foo.clj:5)> On the other hand if it's javax.swing.JPanel it works: (defmacro make-hinted-caller [name class meth] (let [x (gensym)] `(defn ~name [~(with-meta x {:tag class})] (~meth ~x)))) user=> (defn foo [x] (.getUI x)) #'user/foo user=> (foo 3) #<CompilerException java.lang.IllegalArgumentException: No matching field found: getUI for class java.lang.Integer (NO_SOURCE_FILE:228)> user=> (make-hinted-caller foo javax.swing.JPanel .getUI) #'user/foo user=> (foo 3) #<CompilerException java.lang.ClassCastException: java.lang.Integer cannot be cast to javax.swing.JPanel (NO_SOURCE_FILE:230)> user=> (JPanel.) #<CompilerException java.lang.IllegalArgumentException: Unable to resolve classname: JPanel (NO_SOURCE_FILE:232)> user=> (make-hinted-caller foo JPanel .getUI) #<CompilerException java.lang.IllegalArgumentException: Unable to resolve classname: JPanel (NO_SOURCE_FILE:233)> The first exception is easily recognized as one thrown by the reflection API. Without the hint the .getUI call goes through reflection. The second exception is a normal ClassCastException from trying to coerce an Integer to a JPanel. This shows that the make-hinted-caller macro replaced foo with a type-hinted version that expects a JPanel. The third exception shows that JPanel had not been :imported into the user namespace in that REPL instance. The fourth exception is the result of trying to use the unqualified name in the macro. Here's the exception happening if a macro that hints an arg as JPanel is defined in one namespace WITH JPanel imported and used in another WITHOUT the import: user=> (ns foo (:import (javax.swing JPanel))) javax.swing.JPanel foo=> (defmacro make-hinted-getui-caller [name] (let [x (gensym)] `(defn ~name [~(with-meta x {:tag 'JPanel})] (.getUI ~x)))) #'foo/make-hinted-getui-caller foo=> (ns bar) nil bar=> (foo/make-hinted-getui-caller foo) #<CompilerException java.lang.IllegalArgumentException: Unable to resolve classname: JPanel (NO_SOURCE_FILE:245)> bar=> -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en