Nullity (was: User model stacking: current status)
Kevin Bourrillion
kevinb at google.com
Thu May 12 15:25:52 UTC 2022
On Thu, May 12, 2022 at 5:22 AM Brian Goetz <brian.goetz at oracle.com> wrote:
> - there is a nullability-injecting conversion from T! to T? (this is a
> widening conversion)
>
I think we'd expect full subtyping here, right? It needs to work for
covariant arrays, covariant returns, type argument bounds, etc.
> and then we get to decide: which conversions are allowed in assignment
> context? Clearly a nullability-injecting conversion is OK here (assigning
> String! to String? is clearly OK, it's a widening), so the question is: how
> do you go from `T?` to `T!` ? Options include:
>
> - it's like unboxing, let the assignment through, perhaps with a warning,
> and NPE if it fails
> - require a narrowing cast
>
Yes, I do think we want a cast there (a special operator for it is very
helpful so you don't have to repeat the base type), but as far as I know
the case could be made either way for error vs. warning if the cast isn't
there.
Enter Valhalla:
>
> * (Let's say we have B1, B2a/B3a (atomic), and B2b/B3b ("b"reakable?))
> * On a B3 value type like `int`, `?` would be nonsense and `!` redundant.
> * That's equally true of a B3 value type spelled `Complex.val` (if such a
> thing exists).
> * (assuming `Complex` is ref-default) all three of `Complex`, `Complex?`,
> and `Complex!` have valid and distinct meanings.
>
>
> If we have both .val and nullity annotations I think we are losing. The
> idea here would be that B3.val *is literally spelled* `B3!`. The
> declaration story is unchanged: class B1 / value-based class B2 / [
> non-atomic ] value class B3, for some suitable spellings.
>
I have tried to write the above to account for *that* possibility and for
the subtly different possibility that you don't "spell .val" at all, you
just express your nullability needs and the system optimizes to a value
type when it can.
Now, imagining that we reached this point... would B3a/B3b (as a
> language-level thing) become immediately vestigial?.
>
> Unfortunately not. We need permission to unleash the zero-default type,
> because many B2 types (e.g., LocalDate) have no good zero. So B3 is needed
> to unlock that.
>
(Sorry to be a skipping record, but *no* type has a great default value.
It's just about tolerable levels of badness. We tolerate `long` and will
tolerate `ulong` because we're habituated to it. At best it is sometimes a
tiny convenience. It's never exactly an *advantage* to be unable to
distinguish whether a variable was ever initialized.)
But, suppose the *class* is identifiable in some way as friendly to that
default value. I'm still struggling to think through whether we also
strictly need to have something at the use site equivalent to `.val`. Or if
just knowing the nullness bit is enough. It may be fundamentally the same
question you're asking; I'm not sure.
What this short discussion has revealed is that there really are two
> interpretations of non-null here:
>
> - In the traditional cardinality-based interpretation, T! means: "a
> reference, but it definitely holds an instance of T, so you better have
> initialized it properly"
> - In the B3 interpretation, it means: "the zero (uninitialized,
> not-run-through-the-ctor) value is a valid value, so you don't need to have
> initialized it."
>
I'm not sure these are that different. I think that as types they are the
same. It's the conjuring of default values, specifically, that differs: we
can do it for B2, B3, and B3!, and we don't know how to find one for B2!.
But that's not a complication, it's just precisely what we're saying B2
exists for: to stop that from happening.
--
Kevin Bourrillion | Java Librarian | Google, Inc. | kevinb at google.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/valhalla-spec-experts/attachments/20220512/3d58ab34/attachment-0001.htm>
More information about the valhalla-spec-experts
mailing list