We need help to migrate from bucket 1 to 2; and, the == problem
Kevin Bourrillion
kevinb at google.com
Tue Apr 26 03:12:54 UTC 2022
So I want to make my class identityless. But -- whoops! -- I released it
years ago and it has lots of usages. And though I've labeled it as
"value-based", any number of these callers are depending on its identity in
some way or other.
I'd like to put -- let's say an annotation on my class, like
`@_FutureNonIdentityClass` or whatever, with the following effects:
* I get a warning if I'm breaking any of the rules of identityless classes,
like if I have a non-final field.
* Use sites get a warning if they do _anything_ identity-dependent with it
(==, identity hc, synchronization, ...?)
This would leave me in a good position to add the real identity-forsaking
keyword later (at which time the annotation becomes redundant and should
cause a warning until it's removed).
We can address all this in Error Prone, but I'm not sure it should be left
to that, partly because a bunch of JDK value-based types need this same
treatment themselves (apparently only the synchronization warning has been
rolled out so far?).
Could we get this supported in javac itself? The best thing would be to
roll it out in an even earlier release than bucket 2 types themselves...
the sooner the better (maybe we could help?).
I think the annotation could be relegated to some one-off module so it
doesn't pollute the beautiful jdk.base forever.
~~~
One of the things this means is that people should stop using `==` on these
value-based classes.
And that is really really good, because what we are planning to do to `==`
is... really really bad. Don't misread me: if compatibility is sacrosanct
then it is probably the least-bad thing we can do! But honestly, it's bad,
because it's not a behavior that anyone ever *actually wants* -- unless
they just happen to have no fields of reference types at all. But the fact
that it does work in that case just makes the whole thing worse, because
code like that will be a ticking time bomb waiting to do the wrong thing as
soon as one reference-type field is added at any nested level below that
point.
What if we give users support for their migration path, so there *are no*
usages of `==` that need to remain compatible for these types? Then we
could make `==` *not do anything* at all for bucket-2 classes.
This approach could save us from a lot of pain (longstanding pain and new
pain) for int and Integer and friends too.
I think Java's historical priority of "compatibility at all costs" has been
something of an illusion; it still leaves us high and dry when *we* want to
adopt new features as *we* end up having to make incompatible changes to do
it. But if we always gave proper support to users' migration scenarios
then we wouldn't always *need* the absolute compatibility at the language
level.
~~~
(Just to try to move the old overton window, what I really think we should
do is go further and deprecate `==` entirely, introducing
`System.identityEquals(a, b)` (or maybe `===`) which would only work for
identity types. Then in time `==` could be reintroduced as a synonym for
`Object.equals()` and everyone would be happy and write shiny bug-free
programs.... I know this would be a large deal. Sometime I will have to
write at length about just how bad the problem of identity-equality
overuse/abuse has been.)
--
Kevin Bourrillion | Java Librarian | Google, Inc. | kevinb at google.com
More information about the valhalla-spec-observers
mailing list