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

Reply via email to