Reader mail bag

Brian Goetz brian.goetz at oracle.com
Wed Jan 5 12:58:45 UTC 2022


The below was received on the valhalla-spec-comments list; replying here 
as it would have been suitable for this list.

> I am very excited about Valhalla and what it will do for Java. I was
> wondering if the language proposals could be simplified a little bit
> without affecting performance.
>
> Please let me (maybe the community) know if the proposal below could be
> applied or not.
>
> From the new proposal that separates the user type in 3 Buckets (1, 2, 3),
> I believe the Primitive.ref (Bucket 3) and value class (Bucket 2) are
> equivalent, right?

Correct.  The reference companion P.ref of a primitive class P behaves 
like a value class.

> If so, I was wondering if we could have just one class declaration and
> distinguish the variable from how it is created.
>
> The runtime variable would be a value object if we use the new keyword to
> instantiate the variable, if not would be primitive value. I think it 
> makes
> a little bit of sense since the new is used to create an object today,
> right?

The distinction between a Point and a Point.ref is similar, 
semantically, to the difference between a long and a Long:

  - long is a direct value, Long is a reference to an object
  - because long is a large direct value, it can tear under race
  - because Long is a reference, it gets initialization safety guarantees
  - because Long is a reference, it can be null

What's different from today's long/Long story is that, by dropping 
identity, the VM is free to inline Point (and even Point.ref, to a 
lesser degree) in heap objects, and scalarize them in calling conventions.

But, the important distinction is not how the variable is _created_ -- a 
Point is just its (x, y) fields -- but how it is _stored_.  When you say 
`Point`, you are saying "I'm fine with direct (scalar) storage"; when 
you say `Point.ref`, you are saying "I require reference semantics."  
But its the same Point either way.  When you convert from a Point to a 
Point.ref via widening, all that changes is the constraints on how the 
values are stored, but the result is still `==` to what you started with.

The temptation to try and merge buckets 2 and 3 is understandable, and 
we tried to do so several times.  But each time, something important was 
lost.

> See the example below:
>
> [primitive or value] class Point {
>     int x;
>     int y;
> }
>
> Point p1 = Point(1, 1); // primitive value   - p1 is value of Point. Could
> be defined at compile time as new Point() in the actual proposal;
> Point p2 = new Point(1, 1); // value object - p2 instance of Point.ref.
> Could be defined at compile time as new Point.ref();

Ignoring the specific syntax proposal (presence or absence of `new`, 
which is pretty subtle), what you've just done is made `Point` 
polymorphic, which undermines many of the advantages that Valhalla would 
give.  We are able to optimize both Point and Point.ref in part because 
they are monomorphic.

> Assuming the Point.ref is a subtype of Point, I believe this could be
> possible, right? If necessary, the right type could be defined at compile
> time in some cases.
>
> I do not know if it would have extra cost. I hope not.

Yes, a lot :)

> private Point getPoint(boolean reference) {
>      if (reference)
>           return new Point(1, 1);
>       else
>           return Point(1, 1);
> }
>
> Point p1 = getPoint(true); // p1 runtime is a value object -> Point.ref
>
> The array would be like below.
>
> Point[] ps1 = Point[10];  // assert ps1[0].x == 0
> Point[] ps2 = new Point[10]; // assert ps2[0] == null
>
> In this way primitive variables could be null. I don't think this is a
> problem since the wrapper class looks like it will continue to be 
> nullable.
> For another point of view, the builtin primitives cannot be null. An
> Advantage is that it would not be necessary to include T.ref at the return
> of Map.get.
>
> One doubt is about another [primitive or value] class that has [primitive
> or value] members like shown below.
>
> [primitive or value] class Rectangle {
>     Point low;
>     Point high;
> }
>
> Maybe it would be a problem because the object size could not be defined
> previously. But we may assume in this case the size of primitive value.
> This way, Rectangle would be flat.
>
> Thanks for your time and please let me know your thoughts about this
> proposal.



More information about the valhalla-dev mailing list