[External] : Re: Consolidating the user model

Brian Goetz brian.goetz at oracle.com
Thu Nov 4 14:56:27 UTC 2021



On 11/4/2021 2:54 AM, Kevin Bourrillion wrote:
>
>
>     Point.ref pr = pv;  // same object… now it’s on the heap, though,
>     with a real live heap header
>     assert pr.getClass() == Point.class;  // same class, but...
>
>
> Why would we even want this? It would be very surprising/puzzling to me.

It's surprising because we're so used to "boxes" being a thing.  But 
let's look at this a bit.

     int n = 3;
     Object asObject = n;

People like that this compiles, and are not forced to say 
`Integer.valueOf(3)`, but autoboxing hides something bad about boxing; 
that the box type is something completely different.  If we weren't so 
steeped in the Culture of Boxing, we'd be surprised that a lowly 
assignment like this changes the type and representation so drastically 
(and as it turns out, unnecessarily.)

Let's compare with what happens with String.

     String aString = new String("foo");
     Object asObj = aString;

This code makes use of both String and Object, but in slightly different 
and overlapping ways.  String in this example is both a static and 
dynamic type.  When we make a new String with the String constructor, we 
are instantiating a new instance whose dynamic type (getClass) is 
String.  Then we assign it to a variable whose static type is String.  
When we then assign that variable to a new variable whose static type is 
Object, nothing is being converted into an Object; the thing in asObj is 
still a String; it's just held in a variable whose *static* type is a 
supertype of String.

But, this isn't a perfect example, because Object is also a dynamic 
type; I can create new Objects with an Object constructor.  So let's 
replace with Comparable:

     String aString = new String("foo");
     Comparable c = aString;

Now, String is both a static and dynamic type, but Comparable is *only a 
static type*.  There are no objects whose report their type as 
Comparable; there are only objects whose type extends Comparable.

Now, let's go back to the integer example.  The assignment here (in the 
current language) takes the primitive value stored in n, and creates a 
whole new, accidental object whose type is different from int.  The only 
saving grace is that you cannot discern the type of int, since you can't 
ask it getClass, but we all know that boxing is a big seam in the 
language, runtime, and reflection.

In the new world, Point.ref is like Comparable; it exists as a static 
type for variables, but there are no objects that are *instances* of 
Point.ref, because its not a concrete type.

     Point p = new Point(3, 4);
     Point.ref asRef = p;

This is like the String to Comparable example; the new variable refers 
to the same object, but through an alias that has a different static type.

Now, alias is a funny word to use here, but this connects back to the 
whole point of Valhalla -- the reason we disavow identity is that we are 
no longer constrained to track the fact that two references were 
initially assigned from the same object instance. In the absence of 
identity, we're free to copy the state rather than the reference, which 
admits powerful optimizations.  But in the Point example above, it 
really makes sense to think of the Point.ref as a reference to the *same 
instance* that is held by p.



More information about the valhalla-spec-observers mailing list