Search code examples
javaclojurejnr

How to use defrecord in Clojure to extend a Java class?


From my research, the way to extend a Java class is basically with either gen-class in a namespace or with proxy. But looking at the Clojure type selection flowchart, it seems to suggest that I can use record to extend a Java class:

  1. Will the type need to extend a Java class or implement any interfaces? Yes
  2. Do you need a named type or only an instance of an anonymous type? Named type
  3. Do you need to be able to refer to the class statically from Java? No
  4. Is your class modelling a domain value - thus benefiting from hasmap-like functionality and sematics? Yes

Use defrecord

So the question is... how?

For example (from this):

public final class Second extends Struct {
    public final Signed32 a_number = new Signed32();
    public Second(final Runtime runtime) {
        super(runtime);
    }
}

public final class Top extends Struct {              
    public final Second second = inner(new Second(getRuntime()));  
    public final Second[] seconds = array(new Second[5]);
    public final Signed32 another_number = new Signed32();
    public final Signed32[] more_numbers = array(new Signed32[5]);
    public Top(final Runtime runtime) {
        super(runtime);
    }
}

Do I...

(defrecord Second)
(extend jnr.ffi.Struct
        Second)

?


Solution

  • I think the flow chart is wrong. Checking the Clojure - Datatypes: deftype, defrecord and reify documentation we can see that:

    • a deftype/defrecord can implement one or more protocols and/or interfaces

    There is no mention of extending an existing class. Indeed, looking at the documentation for defrecord itself there is no mention of extending existing classes, except for Object as a special case.

    Sorry, it looks like either proxy or gen-class are your only options.