Migrating library classes to value classes
Kevin Bourrillion
kevinb9n at gmail.com
Fri Mar 15 00:13:47 UTC 2024
Sorry for delay.
I've raised a complex topic. Most of what I say in here will need more deep
thought and discussion. I don't even have the vocabulary for half of it.
As a general point: whenever we say "the user can wait for Java N",
sometimes that really means "the user can wait until they're ready to
de-support Java N-1" which is a lot longer time. And, it's not about "I
don't want to wait", but more about "I want to be able to serve the Java N+
users I have right now today and I can't yet".
On Mon, Mar 4, 2024 at 2:26 PM Dan Smith <daniel.smith at oracle.com> wrote:
In the JDK, we are very concerned about compatibility, so we defined
> "value-based class" to require private (or non-private deprecated)
> constructors and construction via identity-ambiguous factories. This
> provides a specified basis for most of the behavioral changes that come
> with 'value', except for the fail-fast behavior of synchronization.
>
Ah I forgot to reference that. Yes, I'm talking about making that same
concept more official/enforceable. (aside: we can backpedal from
the constructor part of it now, right?)
1) Things that can be controlled by the class declaration
>
> There are the basic class structure things (fields, sub- and
> superclasses). These are pretty self-evident—if you've got a candidate
> class, you probably already meet these requirements. In anticipation of
> 'value' coming, maybe you'd like to add some 'final' modifiers in the right
> place for things that were not explicitly final before.
>
> Surely if you're prepared to abandon identity, you've already overridden
> equals/hashCode to support a notion of equality that isn't identity-based.
> 'toString' probably, too, although I think you can assume your users
> won't/shouldn't depend on the contents of the random number appearing in
> the default 'toString' output.
>
When a user first goes through some classes to decide which to make value
classes (whether by keyword or by annotation), I think they're likely
enough to uncover various problems they have to resolve. This is who I'm
thinking about. I think the sooner they can disavow identity and be
prompted to fix up those problems, the better. Partly because the
enforcement they'd get is healthy for their codebase *anyway* even if they
never upgrade to value classes. And partly it just defrays effort they'd
have to do later, and makes the upgrade itself go smoothly. (But these
aren't the whole point.)
Back to the record classes example: if someone can't get on Java 16 yet, I
try to nudge <https://twitter.com/kevinb9n/status/1768366963087331713> them
to use AutoValue, which even has specific advice
<https://github.com/google/auto/blob/main/value/userguide/records.md> to
keep your classes forward-compatible with their future recordy selves.
These users would basically be "pre-adopting" records, which I think is
cool (including in ways I haven't 100% articulated yet).
> Would it be useful to have some tooling that checks all of these things
> for you? Eh, maybe. I'm not sure there's that much to check—most of it
> pretty naturally flows from the fact that you're declaring a class that
> fits in the value-candidate bucket; and making a deliberate choice to avoid
> identity guarantees via factory-based construction and some extra javadoc
> is no harder than making a deliberate choice to add a '@ValueBased'
> annotation.
>
Perfect, so this is the specific part I'm calling into question. Most code
in the world isn't super-well-thought out (and just wait until AI is
writing it all haha). The code just happens to seem to work. If a project
wants to do better, the only practical ways is with the help of one tool or
another. In plenty of cases it's fine to leave that to third-party tools;
I'm wondering whether this is one of them or not.
2) Corner-case use site failures
>
> The main purpose of JEP 390 was to more strongly discourage
> synchronization on types like Integer, because that code will break when
> Integer becomes a value class. I think that's already a corner case—most
> people do not write code like this. But java.lang.Integer gets used by
> everyone, and so an occasionally usage is bound to show up.
>
> s/Integer/SomeLibraryClass/ and I think we're talking about orders of
> magnitude fewer use cases.
I'm more interested in whether it should warn on `==`!
Yes, I do think (with a very appropriate retcon) that Valhalla's change to
it is as compatible as can be (uh ignore float). But, I'm still as
concerned about new-`==` as I was a couple years ago. On most
should-be-value classes today, `==` is flat-out wrong. Tomorrow, it's just
as incorrect -- except it will *happen to work* more often, maybe much more
often. I think it will become an "attractive nuisance", and that the sooner
we can spur people to stop using `==` on classes that are or intend to
become value classes, the better.
When we were working out the details of JEP 390, we considered making the
> @ValueBased annotation public/standard, and decided against it, because we
> wanted to avoid introducing layers of new concepts for programmers. "How is
> a value-based class different from a value class?" is not something we want
> showing up in Java tutorials.
>
Hmm. I would hope this could be simple. A developer makes the same decision
either way, and they just use whichever of `value` or `@ValueBased` is
available to them.
Instead—and I realize this is totally theoretical for me and very practical
> for you, so I appreciate any hard-earned wisdom you can provide—I'm not
> that concerned about saying version N of a library migrates some classes to
> be true value classes, and that should be just fine for most of their
> users. If somebody has a special issue with synchronization or ==, they
> should stick with library version N-1 until they can fix it.
>
I have work to do in explaining what hurts me about this.
> 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.
>
> Our normal approach to javac would be to put new warnings in the latest
> version only. Best we could do is, say, javac 23. And since we expect
> support for value classes to follow soon after, most of the benefit would
> be to people who write, e.g., 17- or 21-targeted code, but compile it using
> the latest JDK.
>
(Why *not* do it sooner, particularly if it's a helpful thing anyway?)
And whenever we talk about something following "soon after", I just think
about the fact that the version in between is out there in the world being
used *forever*...
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/valhalla-spec-experts/attachments/20240314/4bf76f67/attachment-0001.htm>
More information about the valhalla-spec-experts
mailing list