P.val as a no-nulls flag
John Bossons
jbossons at gmail.com
Wed Dec 28 16:02:15 UTC 2022
*> A pretty clear decision that has emerged is that for both*
*>*
*> value class V { }*
*> and*
*> primitive class P { }*
*>*
*> the language-level types V and P are *reference types* (so P is an
alias *
*> for P.ref in the ref/val model.) I won't rehash the arguments in favor *
*> and against here, but this means any "unadorned" type is a reference *
*> type, regardless of whether it is an identity, value, or primitive *
*> class. In this way, all primitive/value classes are "ref favoring",
and *
*> there's no explicit way to flip this, so no need for the *
*> ref-default/val-default syntax of a previous round. One of the
benefits *
*> of this is that migration is smoother because migrating an identity *
*> class to either of the new buckets is source- and binary-compatible.*
For backwards compatibility (and greater simplicity) this is clearly a
better solution — it follows the well-known Integer vs int distinction much
more closely — but does this imply that the ‘P.val’ designation will no
longer be available for primitive object fields? (I assume the P.ref
designation is redundant and so can be deleted.) I think the answer has to
be ‘No’, so maybe I’m just asking that the JEP 401 description be updated.
The ability to be able to specify a P field in a value class as a P.val
type allows it to be specified as non-nullable (like being able to specify
a field as either a nullable Integer or non-nullable int). It allows more
efficient storage (no extra bit to denote null or non-null) and so easier
inlining.
It also potentially allows the compiler to automatically cause an NPE or
other appropriate exception to be thrown if a client attempts to
instantiate an object containing a required P.val field with a null input
value. An example:
value class ContactInfo {
private PhoneNumber.val mobile; // required, non-nullable
private PhoneNumber landLine; // nullable, often missing
... // PhoneNumber is a primitive class
ContactInfo(PhoneNumber pn1, PhoneNumber pn2) {
Objects.requireNonNull(pn1, “mobile”);
this.mobile = pn1;
this.landLine = pn2;
}
}
If the constructor is autogenerated (e.g. in a record), will the compiler
augment the byte code to throw an exception if pn1 = null? Or better still,
cause the following client code to be rejected?
PhoneNumber landLine = new PhoneNumber(...);
ContactInfo info = new ContactInfo(null, landLine); // invalid code
It shouldn’t be necessary to have to specifhy ‘.val’ explicitly in
constructor parameters; the compiler has the information in the field type.
Indeed, it would be nice if one could specify any value class field as
non-nullable, *regardless* of whether the field type is a primitive class.
That would enable the compiler and JVM to store/flatten the field without
having to allocate space to store a distinguishing bit for null (and also
to autogenerate an exception if a null is passed for that field to a
constructor). Using the Objects.requireNonNull method alone doesn’t
accomplish the more efficient storage.
Example:
value class ContactInfo {
private nonull EmailAddress email; // required field
...
}
On a different note, the framework now sounds very close to being final.
Any chance of a preview version of value and primitive classes in JDK 21?
(I’m presuming that the preview feature would allow you to do so while
postponing previews of JEP 402 and modified (universal) generics.) Or, if
not primitive classes, value classes alone?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/valhalla-dev/attachments/20221228/43b4d112/attachment.htm>
More information about the valhalla-dev
mailing list