Migrating library classes to value classes
Kevin Bourrillion
kevinb9n at gmail.com
Mon Mar 4 18:56:36 UTC 2024
Hey everyone,
Most language changes affect only implementation code, but a few like
record classes and now value classes are API-affecting: they permit new API
shapes to be expressed, and thereby new ways for a client class to depend
on a library class.
These features are very carefully made backward-compatible, but there's a
sort of second-level backward compatibility as well: can a library owner
fully exploit the feature in a way that is *itself* backward-compatible for
its clients? Looking at things this way brings in a whole host of new
issues (since libraries often get stuck on old versions and often get run
on a wide range of Java versions newer than the one they built and tested
on, among other reasons).
Record classes seem to come out well in this regard. From what I can tell,
there should be many "record-like" classes today that can smoothly become
records that all clients will still compile against and work with. Some
`getFoo()` methods might have to be preserved as pass-throughs to `foo()`
and maybe some details like that, but it looks pretty clean to me (?).
But migrating to a value class is rescinding functionality and so
inherently *not* backward-compatible. So, libraries can only do it via a
multi-step process, over time. This thread is happening because I think
this project probably wants to support that process, but I'm not clear yet
on how it would do so.
If we did nothing else, we'd be counting on something like this JSpecify
feature request <https://github.com/jspecify/jspecify/issues/488> to happen
(please skim that, it helps explain what I'm even talking about in this
thread). If we feel fine about hoping for the best on that front, then you
can skip the rest of this message (I'd shift my argument to petitioning
Oracle to support that effort!). That is, the remainder is motivated by the
assumption that Java itself wants to actively support these migrations.
Anyway: it looks very compelling to me to put that `@ValueClass`
annotation, such as described, into Java itself, and have javac support it
in the very same way it's going to support value class validation. (Even,
of course, applying it to Integer and friends.)
I'd even ask whether we could take it a step further. Once Java introduces
the `value` keyword, there is *still* a lot of value (ugh) in having the
annotation, and having it mean *exactly* the same thing, with all the same
effects. This has a feeling of heresy to it, but it does something pretty
powerful I think: it allows library owners to write *forward*-compatible
code, that does the right thing whether its clients are using Java N-1 or
Java N. Which makes the event of its users upgrading to Java N ... a little
closer to a *non-*event.
I suspect this of being reasonable. Since that Java N-1 client won't be
able to use `non-atomic` or `!` or `?` or whatever we're calling the kind
of constructor that makes the class a "never-null" type, I think the Java
N-1 VM is within its rights to do almost nothing about the `value` keyword.
(Perhaps prevent synchronization, and let's stick a pin in a discussion
about equality semantics for the moment.) Which is good because it wouldn't
know *how* to do those things.
In fact, the earlier a version of Java we could backport this annotation
and its javac support to, the better, AFAICT. With each version earlier we
could push it, that much more code gets to become safely forward-compatible
today.
This is a much longer discussion but let me cut this message off here as a
conversation-starter. Please start poking holes!
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/valhalla-spec-observers/attachments/20240304/e00e6fdf/attachment-0001.htm>
More information about the valhalla-spec-observers
mailing list