<html><body><div style="font-family: arial, helvetica, sans-serif; font-size: 12pt; color: #000000"><div><br></div><div><br></div><hr id="zwchr" data-marker="__DIVIDER__"><div data-marker="__HEADERS__"><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><b>From: </b>"Kevin Bourrillion" <kevinb9n@gmail.com><br><b>To: </b>valhalla-spec-experts@openjdk.org<br><b>Sent: </b>Monday, March 4, 2024 7:56:36 PM<br><b>Subject: </b>Migrating library classes to value classes<br></blockquote></div><div data-marker="__QUOTED_TEXT__"><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><div dir="ltr">Hey everyone,<br><div>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.</div><br><div>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).</div><br><div>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 (?).</div><br><div>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.</div><br><div>If we did nothing else, we'd be counting on something like <a href="https://github.com/jspecify/jspecify/issues/488" target="_blank">this JSpecify feature request</a> 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.</div><br><div>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.)</div><br><div>I'd even ask whether we could take it a step further. Once Java introduces the `value` keyword, there is <i>still</i> 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 <i>forward</i>-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 <i>non-</i>event.</div><br><div>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 <i>how</i> to do those things.</div><br><div>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.</div><br><div>This is a much longer discussion but let me cut this message off here as a conversation-starter. Please start poking holes!</div></div></blockquote><div><br></div><div>I do not think you need support of javac (i.e. change the spec) for that because we already have the multi-release jar, and a multi-release jar is basically a forward-compatible vehicle for libraries.</div><div><br data-mce-bogus="1"></div><div><div>Using a multi-release jar that uses preview features has been used in the past by several opensource projects, the most popular is, i believe, Lucene that uses the preview versions of Panama to manage (unmap) mmap files.</div></div><div><br data-mce-bogus="1"></div><div>For a class that you want to see both as an identity class and a value class, either you use Maven or Gradle (see [1]) but you have to hand manage the different versions or you use a special bytecode rewriter that look for annotations internal to your project and duplicate the classes (it seems a good use case for the classfile API) with one version being an identity class and one version being a value classes. And you can generalize that approach using JSpecify annotations for tagging fields/parameters that uses value classes with an implicit constructor.<br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><div>I've used the bytecode rewriter approach in my project civilizer [2], which is based on a previous version of Valhalla (the last binary preview) and it works well.<br data-mce-bogus="1"></div><div>  </div><div>RĂ©mi<br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><div>[1] <a href="https://maven.apache.org/plugins/maven-compiler-plugin/multirelease.html">https://maven.apache.org/plugins/maven-compiler-plugin/multirelease.html</a><br data-mce-bogus="1"></div><div>[2] <a href="https://github.com/forax/civilizer">https://github.com/forax/civilizer</a><br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div></div></div></body></html>