New candidate JEP: 468: Derived Record Creation (Preview)

Brian Goetz brian.goetz at oracle.com
Tue Apr 23 13:34:16 UTC 2024


So, a further thing to keep in mind is that currently, adding fields to records is not even source compatible to begin with.  For example, if we have

    record Point(int x, int y) { }

And a client uses it in a pattern match:

    case Point(int x, int y):

And then we add an `int z` component, the client will break.  (When we are able to declare deconstruction patterns, such a migration could include an XY pattern as well as constructor, but we are not there yet.)

I think your mail rests on the assumption that it should be fine to modify records willy-nilly and expect compatibility without a recompile-the-world, but I think this is a questionable assumption.  Records will likely have features that ordinary classes do not yet have access to for a while, making such changes risky.


On Apr 20, 2024, at 5:49 PM, Attila Kelemen <attila.kelemen85 at gmail.com<mailto:attila.kelemen85 at gmail.com>> wrote:

I have a backward compatibility concern about this JEP. Consider that I have the following record:

`record MyRecord(int x, int y) { }`

One day I realize that I need that 3rd property which I want to add in a backward compatible way, which I will do the following way:

```
record MyRecord(int x, int y, int z) {
    public MyRecord(int x, int y) {
        this(x, y, 0);
    }
}
```

As far as I understand, this will still remain binary compatible. However, if I didn't miss anything, then this JEP makes it non-source compatible, because someone might wrote the following code:

```
var obj1 = new MyRecord(1, 2);
int z = 26;
var obj2 = obj1 with { y = z; }
```

If this code is compiled again, then it will compile without error, but while in the first version `obj2.y == 26`, now `obj2.y == 0`. This seems rather nasty to me because I was once bitten by this in Gradle (I can't recall if it was Groovy or Kotlin, but it doesn't really matter), where this is a threat, and you have to be very careful adding a new property in plugin extensions with a too generic name. Even though Gradle scripts are far less prone to this, since those scripts are usually a lot less complicated than normal code.

I saw in the JEP that on the left hand side of the assignment this issue can't happen, but as far as I can see the above problem is not prevented.

My proposal would be to, instead of shadowing variables, raise a compile time error when the property name would shadow another variable. Though that still leaves the above example backward incompatible, but at least I would be notified of it by the compiler, instead of the compiler silently creating a bug.

Another solution would be that the shadowing is done in the opposite order, and the `int z = 26;` shadows the record property (with a potential warning). In this case it would be even source compatible, if I didn't miss something.

Attila

Mark Reinhold <mark.reinhold at oracle.com<mailto:mark.reinhold at oracle.com>> ezt írta (időpont: 2024. febr. 28., Sze, 21:04):
https://openjdk.org/jeps/468

  Summary: Enhance the Java language with derived creation for
  records. Records are immutable objects, so developers frequently create
  new records from old records to model new data. Derived creation
  streamlines code by deriving a new record from an existing record,
  specifying only the components that are different. This is a preview
  language feature.

- Mark

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20240423/b90c07dc/attachment-0001.htm>


More information about the amber-dev mailing list