Hi all,
Let say we have a Point with 2 components
record Point(int x, int y) { }
Then we change the record to add a 3rd components in a more or less backward
compatible way
record Point(int x, int y, int z) {
Point(int x, int y) {
this(x, y, 0); // creation of the new value 0
}
}
Now, let say there is a 'with' somewhere in another code
var newPoint = point with { x = 3; };
If this code is compiled when the record Point had only two components, so this
is equivalent to
Point(int x, int y) = point; // i.e. int x = point.x(); int y = point.y();
x = 3;
var newPoint = new Point(x, y);
The problem is that if we run that code with the new version of Point (the one
with 3 components),
newPoint.z is not equals to point.z but to 0, so once there is a 'with'
somewhere, there is no backward compatibility anymore.
We can try to restore the backward compatibility by compiling to a slightly
different code using invokedynamic and a desugared method corresponding to the
body of the 'with'
var newPoint = invokedynamic (point) [desugared$method]; // equivalent to a
call using with
static Point desugared$method(int x, int y, MethodHandle mh) { // content of
the body
x = 3;
return mh.invokeExact(x, y);
}
an at runtime, we generate a tree of method handles that does more or less
stub(Point point) {
return desugared$method(point.x(), point.y(), (a, b) -> new Point(a, b,
point.z())
}
because this code is generated at runtime, it will be always compatible with
the latest version of Point.
If we want to support this encoding, it means that the local variables of the
enclosing method need to be effectively final so the body of with can be lifted
to a private static method (exactly like a lambda).
If we generalize this a bit, we can also use the same trick for the record
pattern, in that case the pattern Point(int a, int b) is equivalent at runtime
to Point(int a, int b, _) once the runtime found that the canonical
deconstructor emits the values of 3 components.
I'm not sure it's a path i want to follow because i would prefer the record
pattern to match the shape excatly, but i find it more attractive than the idea
to have overloaded deconstructors.
regards,
Rémi