How to implement a record de-constructor ?

Remi Forax forax at univ-mlv.fr
Tue Mar 20 13:38:30 UTC 2018


While a de-constructor is not strictly needed until we want to serialize a record or do Pattern matching on it,
i think it can be useful to share what i think about implementing a de-constructor.

Technically a de-constructor is the inverse operation of a constructor (hence the name), instead of being a function (int, int) -> Point, it's a function Point -> (int, int).

In Java, it's something like this:
  record Point(int x, int y) {
    public (int, int) <deconstructor>() {
      return (x, y);
    }
  }

The issue is that there is no tuple in Java, so writing a de-constructor now is not easy.
Valhalla is currently adding value type, and a tuple is a kind of anonymous value type, so while at some point in the future, Java will have tuples, delaying the introduction of records until we have tuples is not something we should do.

So we have two ways to deal with the implementation of a de-constructor:
1/ internally, toString/equals or hashCode implementation of a record are already using a form of de-constructor as an array of method handles, one by fields, so a de-constructor is seen an an array of getters. We can add a method in the Reflection API, by example, on java.lang.Class that returns this array of method handles. In term of implementation, one can use a constant dynamic to create an immutable list of method handles and just need a way to poke this constant pool constant by example by storing the constant pool index in a class attribute.
2/ we can code the deconstructor in a way that let the calling code of the de-constructor to choose which kind of object it want to return, like this:
  record Point(int x, int y) {
    public Object <deconstructor>(MethodHandle mh, Object o) {
      return mh.invokeExact(o, x, y);
    }
  }
java.lang.Object being the root for all types in Java, value types or not, this will abstract the construction of a value type in the future.
Sending a method handle as also the advantage that instead of creating a tuple, it can also be used to by example the the values inside a ByteBuffer (or any output stream), but for that we need to pass the ByteBuffer as a parameter hence the parameter o.
This design as also the advantage of being compatible with the extractor of Scala, or any API that box the field values into one or more objects.

regards,
Rémi


More information about the amber-spec-experts mailing list