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