value type hygiene

John Rose john.r.rose at
Tue May 15 20:27:13 UTC 2018

On May 15, 2018, at 1:05 AM, forax at wrote:
> ...
> You must admit this use of supers to carry nullable values is possible,
> but you are saying (I think) that you don't agree that this is useful.
> We have already decided that j.l.Object is the super that can carry null, so yes, we do not need another one.

I see.  Yes, the clever ValueRef adds mainly static checking, because it can
carry a type parameter.  Other than that, it is just another Object.

…We could also play this move:  An interface ValueRef<VT> could be defined
such that, at the JVM level, the JVM enforces that (x instanceof ValueRef)
if and only if (x.getClass().isValue()).  The JVM would simply enforce the
corresondence at class load time.   It's a play I'm keeping in my pocket,
which could add special runtime strength to a static typing story.

> ...
> In a sense, you're right, asking for nullability comes with a high cost, it's not flattenable (otherwise you can not store null), acmp => false (it's a value type at runtime) but you still have the fact that JITs that can spill a nullable value type in registers which is an important case. The idea is that even if a nullable value type escapes, the JIT doesn't have to keep it, it can spread it into its multiple components and gather it when it escapes.
> If you take a look to Optional or LocalDate, i'm not sure the need for flattening is that important, but being able to consider it has a value type inside an inlining blob (inside a function of the generated assembly) is important in term of performance when you do operation like map()/filter() or plus*()/minus*(). 

This is an interesting tricky point.  I'm glad it's moot for 99.9% of value types,
which are the non-migrated ones.

Dan's objections to non-nullable migrated arrays would be met, at very high
performance cost, by making arrays of these types nullable also.  What do
you think about flattening arrays of these specially marked VTs (that were
VBCs)?  If we *don't* flatten arrays of a particular VT, then we need a special
way to convey that decision to the JVM.

(I wonder if Panama vector types would tolerate such a move:  We mainly
need in-loop optimizations, so nullability would be tolerable there, but having
them boxed in arrays would be a non-starter.)

> 0. leave it alone, it's a VBC
> 1. make it a proper value type, get flattening on recompile, and deal with the null hygiene fallout
> 0.1 make it a value type but mark it @VBC, no sync or acmp, no flattening either
> but it's nullable, the semantics is simple and mostly backward compatible (== does not work, use equals instead, do not synchronize on it) and no allocation cost where it can be important like in loops.
> in my opinion, yes, it's a trade off, but it's closer to 0.5 than 0.1.  

OK, I see how it is worth the experiment.  It's nice that (except for the
array question) it's purely in the translation strategy:  The existing proposed
ValueTypes attribute would (as you say) simply never mention such a
marked VT.

> The use-site choices for VTs are:
> 0. what choice?  you didn't want that API point anyway
> 1. Object is the untyped workaround for all your nullable needs
> 1.2 clever ValueRef<VT> is your statically typed workaround for nullables
> at the cost of some oddities like what ValueRef<?> or ValueRef.class means.

See above:  It would mean "this is any value type".  Surely that's useful?
We already have reflective Class.isValue, and this would be the static type
for the same concept.  (You see I'm reluctant to kill this "darling"[1].)


> 2. Q-world:  ad hoc variations everywhere between L-VT and Q-VT (cost += 1e6)
> 3. some sugar like VT.BOX or an annotation for one of the previous
> and in all cases, each use-site choice means that people will have to annotate their code to make it works like it were working before with respect of null, so it's not really a practical option because Optional is so widespread in the code that all the codes that contains Optional will never be rewritten. 

We're in a tug-of-war here, between the goal of migratability and
the prime goal of value types (mainly flattenability, of all variables).
One side says "I need to flatten your variable *here*" and the other
side says, "nope, not backward compatible".  Maybe we're proving
that migration is not really possible.  We are certainly proving that
migration is tricky and requires compromising various kinds of
correctness (relative to the pre-migrated semantics).

Ultimately, we must flatten values, except perhaps for a negligible
clearly marked fraction of "compromised values" which dragged
themselves away from VBC-hood, but incompletely.  Ultimately
we must tell the migrators to migrate with semantic changes,
or not migrate.   To paraphrase Yoda, "either do or do not,
but about it don't cry."

— John

More information about the valhalla-spec-observers mailing list