> From: "Kevin Bourrillion" <kev...@google.com>
> To: "valhalla-spec-experts" <valhalla-spec-experts@openjdk.java.net>
> Sent: Monday, April 25, 2022 4:52:50 AM
> Subject: [External] Foo / Foo.ref is a backward default; should be Foo.val / 
> Foo

> Hi,

> The current plan for `primitive class Foo` -- to call the value type `Foo` and
> the reference type `Foo.ref` -- is causing a few problems that I think are
> unnecessary. I've felt for a while now that we are favoring the wrong default.
> We should let `Foo` be the reference type and require `Foo.val` (precise 
> syntax
> aside) for the value type.
> I started to list reasons and came up with more than expected.

If ref is the default for B3 then B3 is a worst B2, it's like saying let's 
transform all long to Long. 

> 1. The option with fewer hazards should usually be the default. Users won't 
> opt
> themselves into extra safety, but they will sometimes opt out of it. Here, the
> value type is the one that has attendant risks -- risk of a bad default value,
> risk of a bad torn value. We want using `Foo.val` to *feel like* cracking open
> the shell of a `Foo` object and using its innards directly. But if it's 
> spelled
> as plain `Foo` it won't "feel like" anything at all.

Users should use B2 by default, you did agree about that. 
if users want B3 we should give them B3, asking for B3.val is a kind of double 
opt-in. 

> 2. In the current plan a `Foo.ref` should be a well-behaved bucket 2 object. 
> But
> it sure looks like that `.ref` is specifically telling it NOT to be -- like
> it's saying "no, VM, *don't* optimize this to be a value even if you can!"
> That's of course not what we mean. With the change I'm proposing, `Foo.val`
> does make sense: it's just saying "hey runtime, while you already *might* have
> represented this as a value, now I'm demanding that you *definitely* do".
> That's a normal kind of a thing to do.

.ref should be rare in the end, it's mostly a stopgap measure because we do not 
have universal generics. 
Once we have universal generics, Foo.val make even less sense. 

> 3. This change would permit compatible migration of an id-less to primitive
> class. It's a no-op, and use sites are free to migrate to the value type if 
> and
> when ready. And if they already expose the type in their API, they are free to
> weigh the costs/benefits of foisting an incompatible change onto *their* 
> users.
> They have facilities like method deprecation to do it with. In the current
> plan, this all seems impossible; you would have to fix all your problematic
> call sites *atomically* with migrating the class.

B3 requires that the default value that makes sense and that bypassing the 
constructor is fine (because you can construct any values by "merging" existing 
values). 
Maybe we should disallow users to even write constructors to avoid to get them 
false hope. 

Anyway, those constraints mean that you will not be able to refactor most of 
the existing classes to a primitive classes because you are loosing 
encapsulation by doing that. 

> 4. It's much (much) easier on the mental model because *every (id-less) class
> works in the exact same way*. Some just *also* give you something extra, 
> that's
> all. This pulls no rugs out from under anyone, which is very very good.

No , B2 and B3 are different runtime models, even if B3 is ref by default. 
The idea of B3 being ref by default is infact dangerous exactly for the reason 
you explain, it looks like the two models are the same. 
The problem is that they are not. 

> 5. The two kinds of types have always been easily distinguishable to date. The
> current plan would change that. But they have important differences
> (nullability vs. the default value chief among them) just as Long and long do,
> and users will need to distinguish them. For example you can spot the 
> redundant
> check easily in `Foo.val foo = ...; / requireNonNull(foo);`.

You want a use site way to see if a type is a B3 as opposed to B1 and B2 that 
are both nullable. 
It's something that can be discussed separately. 

> 6. It's very nice when the *new syntax* corresponds directly to the *new 
> thing*.
> That is, until a casual developer *sees* `.val` for the first time, they won't
> have to worry about it.

But it's not true, compare 
Complex.val c = new Complex(1, 2); 
and 
Complex c = new Complex(1, 2); 

> 7. John seemed to like my last fruit analogy, so consider these two equivalent
> fruit stand signs:

> a) "for $1, get one apple OR one orange . . . with every orange purchased you
> must also take a free apple"
> b) "apples $1 . . . optional free orange with each purchase"

> Enough said I think :-)

> 8. The predefined primitives would need less magic. `int` simply acts like a
> type alias for `Integer.val`, simple as that. This actually shows that the
> whole feature will be easier to learn because it works very nearly how people
> already know primitives to work. Contrast with: we hack it so that what would
> normally be called `Integer` gets called `int` and what normally gets called
> `Integer.ref` or maybe `int.ref` gets called `Integer` ... that is much
> stranger.

int can not be an alias of Integer.val, it's a little more complex than that, 
by example 
int.class.getName().equals("int") 

but at the same time, 
we want ArrayList<int> to be ArrayList<Qjava/lang/Integer>. 

> What are the opposing arguments?

The runtime model of B2 and B3 are not the same. Defaulting B3 to B3.ref make 
things dangerous because users will have trouble to see how B2 and B3 are 
different at runtime. 

RĂ©mi 

Reply via email to