21

I'm trying to generate some Clojure code with type hints, however the type hints seem to disappear whenever I build some code (they also don't function when the code is compiled)

e.g.

`(let [^BufferedImage b (create-buffered-image)] 
   (.getRGB b 0 0))

=> (clojure.core/let [user/b (user/create-buffered-image)] (.getRGB user/b 0 0))

I'm not precisely sure why the type hint is disappearing, but I assume it is something to do with how metatdata is handled by the reader.

What's the right way to create correct type hints in generated code?

Mars
  • 8,689
  • 2
  • 42
  • 70
mikera
  • 105,238
  • 25
  • 256
  • 415

1 Answers1

34

There are two answers to this question. To answer your specific question: in the actual code you just posted, nothing is wrong: it's working just fine. (set! *print-meta* true) and try again, and you'll see the metadata annotation. It just doesn't normally print.

But, in general this is not the right way to do things from a macro, and you will have trouble before long. Remember, you don't want metadata on the forms the macro evaluates, you want metadata on the forms the macro emits. So, a more accurate solution is to use with-meta on the symbols or forms that you want to attach metadata to - or, if they're user-supplied forms, you should usually use vary-meta so that you don't discard the metadata they added explicitly. For example,

(defmacro with-image [name & body]
  (let [tagged-name (vary-meta name assoc :tag `BufferedImage)
    `(let [~tagged-name (create-buffered-image)
       ~@body)))

(with-image i (.getRGB i 0 0))
amalloy
  • 89,153
  • 8
  • 140
  • 205
  • Could you be more specific on "you will have trouble before long"? What kind of trouble? – Dimagog Aug 12 '12 at 20:47
  • Type hints on certain kinds of forms (particularly, IIRC, on lists) will vanish during macroexpansion, if they are put on in the way mikera's question demonstrates rather than the way I suggest. – amalloy Aug 12 '12 at 21:29