Search code examples
clojuremacrosmetaprogrammingcode-generationtype-hinting

Generating Clojure code with macro containing type hints


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?


Solution

  • 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))