The emotional types (T? and T!) are tempting here.  But they are also intrusive.  Once you let them in the house, they want to go everywhere.  And not just on the main floor (language), they want to roam the dungeons too (JVM).  I am a little wary of inviting them into the house just as a way of talking about nullability.

An alternate approach, which I don't yet have a proposals for but am thinking about, is to denote these slightly differently, without putting nulls quote so prominently.  Which is, doubling down on an existing precedent: boxes.  Primitives have boxes, but they're crappy boxes -- they have accidental identity, they are spelled weirdly, they are ad-hoc.  Call them "prototype boxes" -- the hand made ones that you did before you could automate.  The machine-crafted, automated boxes could be sleeker and more uniform.  Then in LW10 you just generify over the box and you're good, since its nullable.  (For LW100, more help is needed.)

There's a massive bikeshed (please let's not try to paint now) for how we would denote value-V separately from box-V.  But this might be a smaller can of worms than T? types.

On 8/29/2018 8:02 PM, Remi Forax wrote:
Hi all,
just to formalize a little more my thinking about the interaction between 
(nullable) value types and erased generics.

With LW1, the VM enforces that a value type can not be null, so each time there 
is a conversion between an Object to a value type, a nullcheck is inserted.
This works great until you start to use already existing code that give a 
meaning to null, like j.u.Map.get is specified to return a V or null,
so a code like this (with Complex a value type)

   Map<String,Complex> map = ...
   Complex complex = map.get("a-key-that-does-not-exist");

throw a NPE before a user can even check if complex is null or not.

 From Java the language point of view, a solution is to have a way to express 
that a value type can be nullable, by mandating a users to write
   Complex? complex = map.get("a-key-that-does-not-exist");
and teach javac how to do a null analysis (guaranteeing that you can not call a 
method on a Type? without a test of null first).

The question is how to translate to bytecode something like Complex?.
We have two choices, one is to teach the VM what Complex? is by adding a bit 
along with field/method descriptor the other is to erase Complex? like we erase 
T (to Object or an interface).

I believe is that we should choose the latter solution
- reifying the null information for the VM means solving the null problem of 
Java not only for value types but for every types, because if we come with a 
partial solution now, it will hamper our design choices if we want to extend it 
latter. And solving the nullablity problem is not one of the goal of valhalla, 
valhalla is hard enough, making it twice hard make no sense.
- having nullable value types reified in the VM is not enough to allow the 
migration between a reference type to a value type, programs will still choke 
on identity, synchronized, etc. But it helps for value based classes, yes, but 
it's the tail wagging the dog. There are few value based classes defined in the 
JDK and we know from the whole module 'experience' that a contract defined in 
the javadoc and not enforced by javac or the VM means nothing.
- erasure works because either a value type comes from a type parameter so it 
is already erased or it comes from a new code so it can be erased because if 
there is a signature clash due to erasure, it's in a new code so the user can 
figure out a way to workaround that.

Note2: because of separate compilations the '?' information need to be 
available in a new attribute (or in an old one by extending it) but only the 
compiler and the reflection will consume it, not the VM.

Note2: we can also restrict further the use of '?' by disallowing to use it in 
method parameter unless it's either on a type variable or in a method 
overriding another one that uses T?, but that a language issue.

Rémi

Reply via email to