There are a few different ways to create Java classes in Clojure, so what are the tradeoffs when picking between gen-class
, proxy
, and reify
in Clojure? (are there other ways to create Java classes that I haven't listed?)
My basic understanding is that I have listed these constructs in decreasing order of power.
Clojure programs get compiled to Java bytecode and executed within a JVM process. Clojure programs also have access to Java libraries, and you can easily interact with them using Clojure's interop facilities.
Clojure has gen-class, reify, proxy and also deftype and defrecord to define new class-like datatypes. For a language that values syntactic simplicity and abhors unnecessary complexity, it seems like an aberration.
The generated class automatically defines all of the non-private methods of its superclasses/interfaces. This parameter can be used to specify the signatures of additional methods of the generated class.
Overview. Clojure was designed to be a hosted language that directly interoperates with its host platform (JVM, CLR and so on). Clojure code is compiled to JVM bytecode. For method calls on Java objects, Clojure compiler will try to emit the same bytecode javac would produce.
Use gen-class
when you want a named class or you want to add new methods to objects you create. gen-class
relies on AOT compilation.
When you want an anonymous, one-off implementation of a type you use reify
or proxy
. They do not rely on AOT compilation. Here are their differences:
reify
only supports protocols or interfaces, proxy
also supports concrete superclasses. reify
uses true class methods, proxy
uses external functions.reify
uses direct method lookup, while proxy
uses a map for method lookup.reify
does not support dynamic swapping of methods, but proxy
does.reify
will perform better than proxy
, so you should always use reify
when possible. Only use proxy
when reify
's constraints are too prohibitive.
In addition to gen-class, proxy and reify, we have defrecord and deftype. These latter two options should be your first choices for the creation of named java classes (and in the case of defrecord, your first choice for any kind of struct with named components.)
The datatypes page on clojure.org is a good reference on this topic. Defrecord, deftype and reify are newer than gen-class and proxy, having been introduced in version 1.2 (I think -- possibly 1.1). Defrecord and deftype both create classes that conform to interfaces, but do not allow for inheritance. If you need inheritance, gen-class (and proxy for anonymous classes) is still your only option.
Defrecord and deftype differ in what you are given for free. Defrecord automatically creates a class which conforms to IPersistentMap and ISeq. Deftype, on the other hand, gives you more control over your class, even allowing for mutable fields (not allowed in defrecord). In general, deftype is intended for low-level implementation of data structures, whereas defrecord is intended for most day-to-day use.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With