Question about universal type variables

Kevin Bourrillion kevinb at google.com
Wed Aug 3 16:44:00 UTC 2022


On Thu, Jul 28, 2022 at 7:35 AM Brian Goetz <brian.goetz at oracle.com> wrote:

On 7/27/2022 5:09 PM, Kevin Bourrillion wrote:
>
> On Wed, Jul 27, 2022 at 12:22 PM Brian Goetz <brian.goetz at oracle.com>
> wrote:
>
>> The main question of this email is: if T is a universal type variable,
>> then *what kind of type* is that? Is it a reftype, a valtype, or
>> something else?
>>
>> It is a type of indeterminate ref-ness or val-ness.
>>
>
> This is to merely assert that Model 1 is correct. But I was asking for a
> fair consideration of both models and a discussion of *why* one is better
> than the other. It's not clear whether that was understood.
>
> I wanted to recap the decisions that we've already made about *how* it
> works,
>

Fine starting point, I was just trying to prompt the second step.


before stepping onto the philosophical playing field.  Its not something
> we've discussed a lot, and wanted to make sure there were no misconceptions
> about how works.  (For example, it's easy to assume that "of course" things
> like `new T[3]` and `new T(foo)` might work under specialization, though
> these are fairly presumptuous assumptions.)
>
> I think this is worth some serious consideration, because having to say
> that there are three kinds of types now in Java would be quite
> disappointing.
>
>
> I don't think that type variables are actually a "kind" of type at all, in
> the way you are thinking.  In type theory,
>

I'm sure the theoretic argument is fine as far as it goes, but it's not
much help for the end user. My issue is with the user model we present to
the world; what "useful fictions" are we securing for them, that enable
them to read and write code with confidence?

I'm sure the notion that T is always a reference type would be initially
surprising to many; maybe enough so that that makes it the wrong model. But
I wanted to (re)state some advantages I see in it. (If some are built on
misunderstandings, I'm hoping to shake those out.)

*Some "T always a reference type" advantages:*

* With subtype polymorphism, the user enjoys a solid understanding that
"reference types are polymorphic, value types are monomorphic". As I'd put
it: you can never have a value (say as a field) without statically knowing
its exact type, because its exact type governs the shape and interpretation
of the bits actually making up the value. Don't know the exact type --> you
need a reference. But parametric polymorphism (thanks for laying out these
terms in the JEP draft, Dan) feels very similar! I'd expect the user to
consult the same intuitions we just drilled into them about subtype
polymorphism. It would be nice if the same simple rule held there too.

* When my class gets used as `MyClass<int>`, I would get to reason like so:
    * When that code runs on some JVM that doesn't do specialization yet,
then my class gets used directly, so those `int`s are really `Integer`s; of
course they are, because T is a reference type. (I expect I can't tear a
value this way.)
    * When that code runs on some JVM that has specialization, then
different "species" of my class are being forked off from my template, each
one physically *replacing* T with some value type. So *those* are value
types, but once again T is still a reference type. (And here I do expect
tearing risk, for non-atomic types.)

* If Java might ever to have non-nullable reference types, I suspect it
might immediately expose this whole type variable issue as having been, at
its essence, never really about ref-vs-val in the first place. What it's
really about is that there used to be one value in the intersection of
every Object type's value set, and now there isn't anymore.

* The best way a user can prepare their generic class for becoming
"universal" in the future is to adopt aftermarket nullness analysis (such
as I'm working on standardizing the semantics for in JSpecify). They'll
mark type parameters like `V extends @Nullable Object`, and methods like
`Map.get` will return `@Nullable V`. That will shake out any obstacles up
front. Then once V becomes a UTP, they'd just change that `V` to `V.ref`,
and they could presumably drop the `@Nullable` too because `.ref` implies
it (why else would it be used?). So the language feature you're introducing
for ref-vs-val universality is immediately doing double duty, capturing
nullness information for reference types too.

This would probably mean rethinking the `T.ref` syntax to something that
more closely evokes "T or null" (the fact this would, for an <int> species,
have to box to `Integer` in the process seems intuitive enough).

-- 
Kevin Bourrillion | Java Librarian | Google, Inc. | kevinb at google.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/valhalla-spec-observers/attachments/20220803/f46e976c/attachment.htm>


More information about the valhalla-spec-observers mailing list