> From: "Brian Goetz" <brian.go...@oracle.com>
> To: "Dan Heidinga" <heidi...@redhat.com>
> Cc: "valhalla-spec-experts" <valhalla-spec-experts@openjdk.java.net>
> Sent: Thursday, April 28, 2022 1:15:08 AM
> Subject: Re: [External] : Re: User model stacking

> Let me try and put some more color on the bike shed (but, again, let’s focus 
> on
> model, not syntax, for now.)

> We have two axes of variation we want to express with non-identity classes:
> atomicity constraints, and whether there is an additional zero-default
> companion type. These can be mostly orthogonal; you can have either, neither,
> or both. We've been previously assuming that "primitiveness" lumps this all
> together; primitives get more flattening, primitives can be
> non-nullable/zero-default, primitives means the good name goes to the "val"
> type. Primitive-ness implicitly flips the "safety vs performance" priority,
> which has been bothering us because primitives also code like a class. So we
> were trying to claw back some atomicity for primitives.

> But also, we're a little unhappy with B2 because B2 comes with _more_ 
> atomicity
> than is necessarily needed; a B2 with no invariants still gets less flattening
> than a B3. That's a little sad. And also that it seems like a gratuitous
> difference, which makes the user model more complicated. So we’re suggesting
> restacking towards:

> - Value classes are those without identity
> - Value classes can be atomic or non-atomic, the default is atomic (safe by
> default)
> - Value classes can further opt into having a "val" projection (name TBD, val 
> is
> probably not it)
> - Val projections are non-nullable, zero-default — this is the only difference
> - Both the ref and val projections inherit the atomicity constraints of the
> class, making atomicity mostly orthogonal to ref/val/zero/null

Now that the model is clearer, let's try to discuss about the val projection. 

Once we have universal generics, we will have an issue with value type with 
zero-default, there are a lot of API in the JDK that explicitly specify that 
they return/pass null as parameter, 
by example, Map.get(), for those call, we need a way to say that the type is 
not T but T | null. 
The current proposal is to use T.ref for that. 

Now, Kevin and Brian thinks that for zero-default value type, in the language, 
Complex.val should be used instead of Complex. 
Lets see how it goes 
1/ There is a difference between Foo and Foo.ref for generics, Foo is a class 
while Foo.ref is a type. 
The idea of using Complex.val means that the relationship is reversed, 
Complex is the type and Complex.val is the class. 
If we ride with that horse, it means that in universal generics, we should not 
use T but T.val apart when we want T.val | null that can be spelled T. 

2/ Because Complex.val is a class and Complex is a type, we have a weird 
dis-symmetry, 
User will declare a class Complex, but to create a Complex, they will have to 
use new Complex.val(). 
As a user this is weird. 

3/ This may change but currently, Foo.class exists but Foo.ref.class is not 
allowed, you have to use a method to get the projection, 
something like Foo.class.getMeTheProjectionPlease(). 
With .val being the default, it means that Complex.val.class exists while 
Complex.class does not. 
Same to get the default value, Complex.class.getDefaultValue() will not 
compile, it should be Complex.val.class.getDefaultValue(). 
Again weird. 

4/ It's a double opt-in, people have to opt-in at declaration site by asking 
for a zero-default value type but that is not enough, 
it only works if the type val is uses at use site. I don't know any feature in 
Java that requires a double opt-in. 

5/ It's easy to forget a ".val". To work, people will have to pepper .val 
everywhere and it will be easy to miss one occurrence. 
Depending on where the ".val" is missed, performance will suffer. This is 
something i see when beginners dab with generics 
for the first times, the compiler emits a warning because they miss one pair of 
<> somewhere in the code. 
To avoid missing , compilers/IDEs will try to rely on null analysis to emit a 
warning when Complex.val should be used instead of Complex. 
Again, the relationship is seen in the wrong direction, with .ref, you get 
performance by default, the compiler does not compile 
if you try to return/store null so by design the compiler helps you to write 
the right code. 

6/ Zero-default value type does not imply non-atomic anymore, 
so a zero-default value type is not more dangerous that a null-default value 
type anymore. 

regards, 
Rémi 

Reply via email to