value type hygiene

forax at forax at
Tue May 15 22:03:52 UTC 2018

> De: "John Rose" <john.r.rose at>
> À: "Remi Forax" <forax at>
> Cc: "Brian Goetz" <brian.goetz at>, "valhalla-spec-experts"
> <valhalla-spec-experts at>
> Envoyé: Mardi 15 Mai 2018 22:27:13
> Objet: Re: value type hygiene

> On May 15, 2018, at 1:05 AM, [ mailto:forax at | 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.

so it's a way to resurect the Qjava/lang/Object; as super type of all value types, it's nullable like Ljava/lang/Object; but you can not put a reference type in it by construction. 

I'm not sure it can solve our problem because at callsite of a method you know the value type and you know that you will call a method that takes a ValueRef so you can the calling convention of a value type but at callee side, you only know that you will be called with a value type but you don't know which one, and passing the class of the value type in the calling convention doesn't seem a good idea, it's what swift does for its generics, and i hope we do not need such complexity for value types. 

>> ...
>> 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.

When you create an array, you can check if it has to be flatten or not using the ValueTypes attributes, if it's possible (see below). 

Or you can for these specific type allow flattening by default and do heroic change if there is a code that try to put null in it by re-boxing all the elements as you said in the message to Maurizio. 
Usually doing heroic things like this in the VM is a stupid idea, here, we are talking about a corner case, how to retrofit value based class, so doing heroic things like this is two times stupid. 

> (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.)

I hope that If the panama vector API is published, it will be as an experimental API so no need to maintain a backward compatibility story here. They can be value types. 

>>> 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.

It can be a pure translation strategy for array too, if the VM uses the attribute ValueTypes to know which kind of array should be created but in that case, it means that the array need to be tagged as flattened or not and i do not know if it's possible. 

>>> 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].)

> [1] [ |
> ]

I can kill it for you :) 
The argument is that we can always re-introduce it in a later release. 

>>> 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