On Mon, Apr 25, 2022 at 1:59 PM Kevin Bourrillion <kev...@google.com> wrote: > > On Mon, Apr 25, 2022 at 1:19 PM Brian Goetz <brian.go...@oracle.com> wrote: >> >> Changing from a B2 -> B3 changes the default spelling from "L" -> "Q". >> Why does this have to be done atomically? > > (First note that I'm thinking in terms of source compatibility, if that makes > a difference.) I mostly just mean that anyone anywhere might be counting on > the type being nullable. Is it possible to fix all that code ahead of time to > be nullness-agnostic, i.e. the very same code works whether the type is > nullable or not? I feel like it would be hard to get *everything* that way.
You're right it's more source compatible assuming that existing descriptors are never updated to use ".val". Old code would keep working while newly added methods could use ".val" to benefit. Once a container is updated to use .val for backing storage then we're dealing with null pollution from those old methods and someone has to do something to adapt. And if storage locations aren't updated, then why migrate the type? I'm not sure this is better? We've eased the identity -> B2 migration path (and ended up in a good spot doing it!) but this may be over-rotating on the migration axis. The main use case I'm aware of for a B2->B3 migration is better memory density in the heap. Converting from our L->Q via checkcast will throw on null (plan of record, correct?). Once we migrate the backing storage to be a B3, we need some answer for the missing null case or we're just leaving a footgun for the users at runtime. >From Brian's email: > The API point has to stay LOptional, but the field could migrate further to > QOptional, and there’s definitely value in that. To migrate, either the field has to grow a ".val" or the descriptor has to grow a ".ref". Someone has to make an explicit choice. As I said above, migration is one use case. The author of B3 api is not going to be happy needing to put ".val" all over their code and neither will their users. primitive value class Complex { long re; long im; static Complex.val add(Complex.val a, Complex.val b) { .... } static Complex.val mul(Complex.val a, Complex.val b) { .... } static Complex.val sub(Complex.val a, Complex.val b) { .... } } Do we want to make this worse to read for the migration use case? --Dan