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

Reply via email to