<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<font size="4"><font face="monospace">There's been a lot of change
since the last update of this JEP, so let me summarize the
changes and the motivation. The current JEP text is still very
rough; the point of sharing it in this state is to sketch out
the next chunk of the story and how it connects to the other
chunks, even if they are not fully fleshed out. <br>
<br>
#### Value and "primitive" classes<br>
<br>
This JEP positions the Valhalla story as one of "the more
flexibility you give up, the better flattening you get."
Identity classes get no flattening. Value classes (B2) give up
identity (but nothing else), and they get better flattening on
the stack (e.g., optimized calling convention), but (absent VM
heroics) no flattening on the heap. This is already confusing
to many users, because they hear "flattening" and think "layout
inlining." <br>
<br>
To get heap flattening / layout inlining, you have to give up
some more. It took a while to figure this out, but we finally
realized that the key distinction between B2 and B3 has to do
with its _initialization protocol_ (or lack thereof).
Non-nullability is important for flattening, but it is
secondary; before you can go non-nullable safely, you have to
obviate the need for null in the first place, which means you
need to make initialization optional. <br>
<br>
We have nulls because most objects require initialization;
simply interpreting a block of zeroed memory as an instance of a
class is usually only incrementally worse than interpreting a
block of garbage as an instance of that class. To protect from
interpreting uninitialized memory as an object instance, object
references use null as their default value. The primitive types
all share the characteristic that the zero value is actually a
good default, and therefore they do not need the extra
initialization safety afforded by object references and null,
and therefore they can be non-nullable, and therefore they can
be routinely flattened. <br>
<br>
With this in mind, we downplay the distinction between B2 and
B3; B3 is a special kind of value class, one for which
construction is optional because the default (zero) value is
considered good. <br>
<br>
#### Performance story<br>
<br>
The performance story becomes one of a spectrum of tradeoffs:<br>
<br>
- Identity classes get lots of flexibility, but no flattening.<br>
<br>
- Value classes give up identity, and get flattening on the
stack (optimized calling convention, reliable scalarization,
etc), but no flattening on the heap. <br>
<br>
- Value classes that support default instances (B3) give up on
the requirement that all instances be initialized, and in
return, non-nullable variables can be flattened in the heap --
up to the limit of atomic load/store operations. <br>
<br>
- B3 classes that further opt out of atomicity can get heap
flattening for larger instances. <br>
<br>
#### Ref, val, and bang<br>
<br>
The previous version of the story divided uses of B3 classes
into a primitive type and a reference type, and there were a
number of properties that derived from the choice of reference
vs primitive (including nullability). We've now arrived at the
point where we can represent these properties individually, and
therefore don't need to appeal to this coarser ref-vs-val
distinction. As a result, we can get rid of the clunky X.ref /
X.val notation, and express null-restriction with the more
familiar cardinality sigil, `X!`. <br>
<br>
For purposes of this JEP, the use of null-restriction types is
limited to types where the null-restriction can be reified by
the JVM (hello, Q types); a separate JEP will explore extending
it to all reference types and the attendant consequences of
erasure (e.g., null pollution.)<br>
<br>
In this interpretation, we do not have to call `Point!` a
primitive type; we can call it a restriction of the reference
type `Point`. (If we do, we gain some uniformity for class
types ("everything is a reference"), at the expense of
permanently living with a more visible seam with primitives; we
can continue to evaluate the tradeoffs here.) <br>
<br>
<br>
</font></font><br>
<div class="moz-cite-prefix">On 3/21/2023 12:10 PM, Dan Smith wrote:<br>
</div>
<blockquote type="cite" cite="mid:B1F741A8-449E-4397-B0B9-5560DD81B62F@oracle.com">
<pre class="moz-quote-pre" wrap="">I've updated JEP 401, formerly "Primitive Classes", now titled "Null-Restricted Value Object Storage". The purpose of this JEP is to allow for flattening of value objects in fields and arrays. This update gets there via two key features:
- "Optional" constructors, which express the capability of a value class to have instances created outside the normal construction process.
- Null-restricted types, which exclude null from the type's value set, and in the case of value classes with optional constructors, allow for a non-null default value.
There's more to say about nullness, which is covered by its own JEP that we're still working on. But the idea of null-restricted variables is enough to unblock progress on value object flattening. (Eventually, we envision—at least for now—delivering the two JEPs at the same time.)
The document is here:
<a class="moz-txt-link-freetext" href="https://openjdk.org/jeps/401">https://openjdk.org/jeps/401</a>
</pre>
</blockquote>
<br>
</body>
</html>