[External] : Re: Revisiting default values
brian.goetz at oracle.com
Thu Jul 1 13:06:33 UTC 2021
> I sincerely claim that your statement is in the same boat. You're
> speaking of what has /happened/ to be the case in Java, because reasons.
> However, I think the /concept/ of null is more basic; it is just
> "there is no instance here". Try to do instance stuff, blow up always,
> that's null.
> If you say it's /fundamental/ to the notion of a primitive/inline type
> that there is /always/ a value there.... okay, but then what you're
> talking about is /bits/. Yep there are always bits there. But is that
> what matters to software? What software wants is programs that are
> first correct and then (as hot on the heels as you like) performant.
I'm saying something slightly different (but I agree it's as much "what
happened" as "what is"). Our formulation of ref/val is based on saying
"well, the instance *is*, but there are two ways to store it, and
nullity is part of the 'how you store it' rather than the 'what it
is'." I think this is a more helpful way to look at it, but of course
it's not the only way. But I want to make sure that we don't select a
set of mental models that are locally sane but conflict with each other.
> I think we are better off treating this as a discussion about
> initialization safety, rather than nullity, until we have a clear
> story of how we want things to behave.
> Sure, I'd be very interested in that discussion too.
By that I mean: framing this not as "this field is null", but instead,
"this field is uninitialized, so it is an error to dereference it." One
could argue (well, it would be a stretch) that the following code is not
String nullIMeanIt = null;
nullIMeanIt.length(); // Gimme an NPE, dammit!
It is obviously *silly*, but by "not broken", what I mean is that
getting an NPE when you dereference a null pointer is *what null does*.
The bug in most NPEs is a null where we didn't expect it, but usually
one that was put there. When we get a NPE from x.foo(), it is often not
the case that we failed to initialize x; we initialized it to something
that unexpectedly returned null *as a value*, such as `x = getBar()`.
All the @NonNull stuff is an attempt to get null to go back in the cage,
after we let it escape. But I think with no-good-default primitives, it
is about not letting the thing escape in the first place. The
difference in practice may be minor, but the difference in the story we
are able to tell as a result might be bigger.
More information about the valhalla-spec-observers