[External] : Re: Consolidating the user model
Brian Goetz
brian.goetz at oracle.com
Tue Nov 2 23:53:38 UTC 2021
> My concern is that the purest form of value types will be overused and
> misused for even less clear-cut cases. I would like to think that we
> can convince these users that they really want the next "bucket" over,
> which I think comes down to whether the added cost of `null` is worth it.
I share this concern. Do you have any thoughts of how to make B2 more
attractive?
For the record, we expect to see similar stack-based and IR-based
flattening across buckets 2 and 3, but measurably less heap-based
flattening for bucket 2. Plus the extra footprint.
> Btw, am I right that for the middle bucket, `==` will fail (at
> compile-time when possible)?
B2 gets state-based ==, just like B3. No difference there; if you have
no identity, then equality is state-based.
>
>
> The third bucket are the _true primitives_. These are also
> identity-free
> classes, but further give rise to both value and reference types,
> and the value
> type is the default (we denote the reference type with the
> familiar `.ref`.)
> Value types are non-nullable, and permit tearing just as existing
> primitives do.
> The `.ref` type has all the affordances of reference types --
> nullability and
> tearing protection.
>
>
> In fact, if I'm looking at a middle-bucket class, and I'm looking at
> one of these `.ref` types of "primitive" class, as far as I can tell I
> should be able to think of these in exactly the same way as exactly
> the same things.
Yes. A B2, and a B3.ref, behave identically.
> (I'm aware you intend to define `==` differently for the two, but I'll
> get into my massive concerns about that later.)
Actually, B2, B3, and B3.ref all have the same interpretation of ==,
which is state-based. (You can think of this as "box (or unbox) before
comparing a B3 with a B3.ref.)
>
> - Null-adjunction. Some methods, like `Map::get`, return null to
> indicate no
> mapping was present. But if in `Map<K,V>`, `V` is not
> nullable, then there
> is no way to express this method. We envision that such
> methods would return
> `V.ref`, so that strict value-based classes would widened to
> their "box" on
> return, and null would indicate no mapping present.
>
>
> Now just spell it `?` :-)
> (not serious. Also, not not serious)
Yeah, maybe. If that were the only difference, I'd be more inclined.
But it drags in ref-ness, and all the reference affordances, so it feels
more misleading than helpful at this point.
>
> ## Reflection
>
> Earlier designs all included some non-intuitive behavior around
> reflection.
> What we'd like to do is align the user-visible types with
> reflection literals
> with descriptors, following the invariant that
>
> new X().getClass() == X.class
>
>
> Seems like part of the goal would be making it fit naturally with the
> current int/Integer relationship (of course, `42.getClass()` is
> uncommitted to any precedent).
There's a nasty tension here. On the one hand, for B3 classes, it makes
sense for b3.getClass() to yield the val mirror, but int.getClass()
historically corresponds to the ref mirror (Object o = 3; o.getClass()
== Integer.class.) To invert it, we would have to break a lot of
reflection-using code that tests for Integer.class because that's how
primitives are reflected. Work in progress.
> Actually, that makes me start to wonder if `getClass()` should be
> another method like `notify` that simply doesn't make sense to call on
> value types. (But we still need the two distinct Class instances per
> class anyway.)
You could argue that it doesn't make sense on the values, but surely it
makes sense on their boxes. But its a thin argument, since classes
extend Object, and we want to treat values as objects (without appealing
to boxing) for purposes of invoking methods, accessing fields, etc. So
getClass() shouldn't be different.
More information about the valhalla-spec-observers
mailing list