Clojure's proxy facility creates a Java class, extends a concrete class or implements interfaces, and immediately returns an instance with functional method overrides. It targets interoperability cases where a Java framework requires inheritance, while capturing surrounding lexical bindings for use in implementations. section 15.5 section 15.0
A proxy combines several operations that can also be controlled separately:
- Pass parent classes and interfaces, constructor arguments, and method-override forms to proxy. section 15.5
- Reuse generated proxy classes when proxies share a signature, while keeping each instance's overridden methods and closed-over variables separate. section 15.5
- Inspect or replace implementations after creation with proxy-mappings or update-proxy. section 15.5
- Separate class generation, construction, and initialization with get-proxy-class, construct-proxy, and init-proxy when lifecycle control matters. section 15.5
Extending java.io.File
(defn cfile [fname] (proxy [File Concatenable] [^String fname] (concat [^File f] (spit (.getPath f) (slurp this) :append true) f))) (def etchosts (cfile "/etc/hosts")) (.concat etchosts f2) The proxy adds concatenation behavior to a File-compatible object without changing the existing interface. update-proxy can later replace concat, for example to create the destination file automatically. section 15.5
Separating proxy lifecycle phases
(def DocumentException (get-proxy-class Exception IDeref)) (-> DocumentException (construct-proxy "message") (init-proxy {"deref" (fn [this] "Cause: message")})) get-proxy-class can prepare reusable classes, construct-proxy selects constructor arguments, and init-proxy installs method overrides. section 15.5
(def ^Runnable r ; #1
(proxy [Runnable] [] ; #2
(run [] (println (rand))))) ; #3
(.run r) ; #4
;; 0.1678203879530764
A minimal Runnable proxy shows the target interface, empty constructor arguments, overridden run method, and immediate invocation. section 15.5
