[Home]

Tricky uses of Clojure gen-class and AOT compilation

Today I was trying to figure out how to use Clojure to generate a class that would override certain methods of the parent class based on either:

It took a little bit of figuring out so I thought I'd write something down for Google to find.

Overriding methods based on cardinality

For this I found I could use multiple arguments forms as desired. Using a proxy:

(def *reader*
     (proxy [java.io.StringReader] ["hello world"]
       (read ([] (proxy-super read))
             ([x y z] 456))))

I can override the implementation of read with three arguments while passing the no-argument version back to the parent:

user=> (. *reader* read)
104

user=> (. *reader* (read (make-array Character/TYPE 5) 0 2))
456

We can do this using gen-class too:

;; Note the tricky use of exposes-methods: this allows you to expose
;; the methods of the parent class under a different name.
(ns net.dishevelled.TestReader
  (:gen-class :extends java.io.StringReader
              :exposes-methods {read readSuper}))

(defn -read 
  ([this] (. this readSuper))
  ([this cbuf off len] 456))

Overriding methods based on type signature

I couldn't see a way of doing this using a proxy, but here's how you can override a method based on the types of its arguments:

(ns net.dishevelled.TestReader
  (:gen-class :extends java.io.StringReader))

;; gen-class looks for a method with argument types in its name for
;; overriding specific method signatures.  The char<> syntax for
;; primitive array types took me a little bit to figure out...
(defn -read-char<>-int-int [this cbuf off len]
  456)

and we can override a method which takes no arguments by giving its type as void:

(defn -read-void [this]
  456)