> From: "Kevin Bourrillion" <kev...@google.com> > To: "valhalla-spec-experts" <valhalla-spec-experts@openjdk.java.net> > Sent: Tuesday, April 26, 2022 5:12:54 AM > Subject: We need help to migrate from bucket 1 to 2; and, the == problem
> 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. >From my experience, there are == that are buried deeply masked as innocuous == >on Object. A simple example is assertSame() of JUnit, it is defined on Object but will call == on B2 if the arguments are B2. Any non-interprocedural analysis will miss them. Perhaps an agent that rewrite all acmp to use invokedynamic will be able to trap those runtime call to == and emit a warning with the corresponding stacktrace. RĂ©mi