with and binary backward compatibility
Remi Forax
forax at univ-mlv.fr
Tue Jun 14 12:22:40 UTC 2022
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
More information about the amber-spec-experts
mailing list