B3, default values, and implicit initialization
Remi Forax
forax at univ-mlv.fr
Tue Mar 28 21:09:59 UTC 2023
> From: "Brian Goetz" <brian.goetz at oracle.com>
> To: "valhalla-spec-experts" <valhalla-spec-experts at openjdk.java.net>
> Sent: Tuesday, March 28, 2023 9:13:02 PM
> Subject: B3, default values, and implicit initialization
> The recent update of JEP 401 contained a number of refinements to the user
> model, specifically, separating the primitive/reference distinction into a
> number of smaller distinctions (e.g., nullable vs non-nullable, optional vs
> required construction.) Overall this has been a very positive step forward.
> We still have a need for the distinction between what we've been calling B2 and
> B3; JEP 401 currently frames that in terms of "construction is optional." This
> is a big step forward; indeed, the key difference between them is whether the
> class _needs_ the "variables start out as null, and all instances are created
> by constructors" protection, or whether it admits the lighter-weight
> initialization protocol of "there's a a standard zero value, null-free
> variables are initialized to that" that primitives enjoy today. (Note that B3
> classes don't require this lighter protocol, they merely enable it, much as
> primitives all give you the option of boxing to get the full conservative
> initialization protocol.)
> The idea of framing this as "construction is optional" is a good one, but the
> expression of it proposed in JEP 401 feels "not quite there". In this note I'll
> propose an alternative presentation, but the main goal here is around
> terminology and user model rather than syntax (so please keep the syntax
> agitation to a reasonable level.)
> The key distinction between B2 and B3 is that B3 has a _default value_ which the
> VM can summon at will. This enables non-nullable heap variables to be
> flattened, because we can initialize these the same way we initialize other
> fields and array elements. Further, that default value is highly constrained;
> it is a physical zero, the result of initializing all fields to their default
> value.
> Flattening is of course a goal, but it is not something that exists in the
> programming model -- its just an optimization. What exists in the programming
> model is the default value, and what this unlocks is the possibility for
> variables to be _implicitly initializated_. Reference-typed variables today are
> _explicitly initialized_; variables start out null and have to be initialized
> with a constructed value. A class with a default value has the option (opted in
> through null-exclusion) for its variables to be implicitly initialized, which,
> like primitives, means that they start out with a valid default value, and can
> be further assigned to.
> Framed this way, the Valhalla performance story simplifies to:
> - Give up identity, get flattening on the stack;
> - Further give up explicit initialization, get flattening for small objects on
> the heap;
> - Further give up atomicity, get flattening for larger objects on the heap.
> Giving up explicit initialization entails both the class opting out of explicit
> initialization, _and_ the variable opting out of nullity.
> The key new terminology that comes out of this is implicit vs explicit
> initialization.
> Syntactically, my preference is to indicate that the default value can be
> summoned by giving a value class a _default constructor_:
> value class Complex {
> public final double re, im;
> public default Complex();
> }
> A default constructor has no arguments, no body, no throws clause, and
> implicitly initializes all fields to their default values. Unlike identity
> classes, value classes don't get constructions implicitly; a value class must
> declare at least one constructor, default or otherwise. This replaces the idea
> of "optional constructor", which is a negative statement about construction
> ("but you don't have to call me"), with a more direct and positive statement
> that there is a _default constructor_ with the required properties.
> Note that this is similar to the existing concept of "default constructor",
> which you get for free in an identity class if you don't specify any
> constructors. It is possible we can unify these features (and also with
> constructors in "agnostic" abstract classes), but first let's work out what it
> would mean in value classes, and see if we like it.
> In this model, a B3 class is just a value class with a default constructor -> a
> default constructor means that you have the choice of implicit or explicit
> initialization -> non-nullity at the use site opts into implicit initialization
> -> B3! gets flattening (for small layouts.)
For me, the notion of default value is clearly better than the notion of optional constructor.
It also works well with the idea of being able to get the default value of a type variable (T.default).
I also really like the idea that the value class semantics is defined in terms of giving up properties even if it is equivalent to getting the VM more leeway.
I fear that in term of syntax we need a little more ceremony because the default constructor may be buried deeply inside the class, far from the declaration of the value class, making the semantics of the class non obvious for readers. I believe, the class should declare a default constructor and should also be annotated with a keyword, a kind of belt and suspender approach.
Or perhaps we can use the "functional interface"/"override" playbook here and not add a new keyword on value class but introduce an annotation similar to @FunctionalInterface/@Override, let say @DefaultValue (or whatever suits better) that documents that there is a default constructor thus a default value.
If this annotation is set on a value class, the compiler will verify that a default constructor is present.
regards,
Rémi
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/valhalla-spec-observers/attachments/20230328/f8e60559/attachment.htm>
More information about the valhalla-spec-observers
mailing list