Revisiting default values
John Rose
john.r.rose at oracle.com
Thu Jul 1 00:00:04 UTC 2021
On Jun 29, 2021, at 2:36 PM, Kevin Bourrillion <kevinb at google.com<mailto:kevinb at google.com>> wrote:
Speaking of orthogonality, there *is* an open question about how we interpret <invalid>, and this is orthogonal to the question of whether <invalid> should be the "default default". We've talked about:
- It's interchangeable with null
- It's null-like (i.e., detected on member access), but distinct
- It's a separate concept, and it is an error to ever read it from fields/arrays
All still on the table.
Oh. Yeah, if you look at all the work we've all poured into how we manage null and its attendant risks, and ongoing work (perhaps charitably assume JSpecify will be successful! :-)), then it's kiiiind of a disaster if there's suddenly a second kind of nullness. #nonewnulls
BTW, the combination of #nonewnulls (a principle
I whole-heartedly favor) and “it is an error to ever
read it” pencils out some capability to define
containers of nullable types but which reject nulls
in some way. (Perhaps a subtle way: Perhaps the
container starts out null but cannot be read
until a different initial value is written.)
Such containers would resemble, in certain
ways, containers for lazily-computed values.
(I.e., they have a dynamically-distinguished
undefined state, and they cannot return to
that state having left it.) OTOH, a container
for a lazily-computed *nullable* value would,
in fact, require a second sentinel, not null,
to denote the unbound state; making that
sentinel escape would create a #newnull,
which would be bad. Not sure how to square
this circle yet.
Another random side-point, this time about
`withfield`: It is IMO impractical to perform
default exclusion (null detection) for field
assignments in primitive class constructors,
because the default-ness of `this` is a complicated
dynamic property of all the fields together.
As a constructor executes, it may temporarily
revert `this` to the default value if it zeroes
out a field. So the `withfield` instruction
should *not* perform default exclusion
on `this`. (Of course an excluded default
would get checked for on exit from the
constructor.)
A similar point goes for `getfield`, perhaps,
though less strongly, because the Java
language would not use it. But the JVMS
should probably attach default exclusion
either to both `withfield` and `getfield`
or neither. This suggests that only method
invocations would perform default exclusion.
Which reminds me: I think we should
allow calls to methods on `this` inside a
constructor. (Do we?) A clean way to
statically exclude incomplete values of `this`
would be to outlaw such self-calls until all
final fields are definitely assigned. The
current language (for identity classes)
computes this point (of complete field
assignment) in order to enforce the rule
that the constructor cannot return until
all final fields have been definitely assigned.
For identity classes it would be nice to
*warn* on self-calls (or perhaps other
uses of `this`) before all finals are DA.
For primitives classes we can outlaw
such things, of course.
Basically, for both primitive and
identity class constructors, it is a likely
bug if you use `this` (for something
other than initializing `this`) before
all final fields are DA. And yet some
constructors perform additional
operations (such as sanity checks)
in an object constructor, when the
object is in DA and “almost finished”
state. It would be smart, I think, to
make the rules in this area, as coherent
as possible, for both kinds of classes.
IIRC the status quo is that no uses of
`this` are legitimate in a constructor
body except field writes (of DU fields)
and field reads (of DA fields). I think
that is too strict, compared to the
laxness of the rules for identity classes,
and given the usefulness of error
checking methods being called from
constructors.
More information about the valhalla-spec-observers
mailing list