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