[External] : Re: Consolidating the user model

Kevin Bourrillion kevinb at google.com
Thu Nov 4 00:19:04 UTC 2021


(Note that shipping bucket-2 shouldn't require us to agree on any of this
stuff below.)


On Wed, Nov 3, 2021 at 4:06 PM Dan Smith <daniel.smith at oracle.com> wrote:

> - provides the exact same API as the original
>> - has the exact same behaviors as the original
>>
>
> Agreed that Point and Point.ref are different types that have the same
> members/features.
>
> One-class-multiple-types is not entirely without precedent (though, sure,
> List<A> and List<?> and List don't have *exactly* the same API).
>
> Once you accept that they're different types, then the fact they have the
> same API is just convenient.
>
>
> - works exactly like a class declared with original class's declaration
>>
>
> It's the same class. There's only one class.
>
> (There are two java.lang.Classes, because what that type models is not
> "class", it's something more like "an erased type or void" <handwave>.)
>
>
> Is your model that, where there are n possible Points, there are in fact
> 2n instances of class Point, where half of them are "values" and half of
> them are "boxes"?
>

... Yes? but it's an odd way to put it; I'll explain. The model I'm
speaking for says that values and objects are two different and disjoint
kinds of things. So there are n possible Point values (according to !=) and
there are n corresponding possible Point.ref objects (according to !=). But
I wouldn't have put the numbers together into one number "2n", because I
don't think there's anything a program could actually count that would turn
up that answer. (It's a biiiit like asking "how many continents or cardinal
directions are there?" and I just answer "11".) Sorry, I belabored that
point a bit overmuch.


I would find that pretty confusing, but I'm not sure it's what you mean. I
> would want to be able to somehow distinguish which subset an instance
> belonged to.
>

I don't see what distinguishing there is to do? You always definitively
either have a value or you have a reference value pointing to some object.
You know that before there's even any question to ask... right?


Or is it your model that, when you convert a value to a box, the two things
> are the same class instance, just manifested or encoded differently?
>
> That's actually not that far from the model we've described, which is that
> it's the same instance, just *viewed* or *accessed* differently. Those are
> different verbs, and so the models might not be interchangeable, but
> they're close.
>
> If you're telling people that when you assign a Point to type Object, they
>> now have something other than a Point, they're going to want to *see* that
>> somehow. And of course they can't, because the box is a fiction.
>>
>
> What would they want to see? What is there to see about an object? Maybe
> its header, its dynamic type -- and uh, those things must be there, right?.
> because how could I use it polymorphically otherwise. I'm not sure what
> else would be meant by "seeing" the thing.
>
>
> I think my intuitions about boxes tie heavily to 'getClass' behavior (or
> some analogous reflective operation). "What are you?" should give me
> different answers for a bare value and a box. A duck in a box is not the
> same thing as a duck.
>
> The analogy here would be that Integer.getClass() returns Integer.class,
> while int.getClass(), if it existed, would return int.class.
>

So far so good. If `int.getClass()` has to work at all, it might as well
produce `int.class`, though it serves no actual purpose and we would just
refactor it to `int.class` anyway. If `int.getClass()` won't even compile,
it would be no great loss at all. The method exists for finding the dynamic
type of an object; my model says "values are not objects and so have no
dynamic type", which I think is good.


I might want to write code like:
>
> <T extends Point.ref> void m(T arg) {
>     if (arg.getClass() == Point.class) System.out.println("I'm a value!");
>     else System.out.println("I'm a box!");
> }
>

Someone might think this, but they can just ask themselves whether
`int/Integer` work like that. They don't, so this doesn't either. This is
one example of why users can *keep* almost everything they already know
about `int/Integer`.


But this isn't the runtime behavior we would intend to support, because in
> fact at runtime there are no boxes to reflect.
>
> I'll attempt to flip this around on you. :-) You say that a *value* of
> type Point is also already an "object". But then where is its header, its
> dynamic type? Objects have that. For whatever reason this seemed like the
> more conspicuous leak to me.
>
> The value type/reference type model is that you can operate on an object
> directly, or by reference. It's the same object either way.
>

I will be writing out my argument for why this is nonsense. :-)  Not meant
to sound rude (I didn't know it to be nonsense myself a month ago).



> Reference conversion just says "take this object and give me a reference
> to it". Nothing about the object itself changes.
>
> The details of object encoding are deliberately left out of the model, but
> it's perfectly fine for you to imagine a header and a dynamic type carried
> around with the object always, both when accessed as a value and when
> accessed via a reference.
>

Huh. It seems to me very important to understand that when I use Point (not
Point.ref) there is no header involved. Values are not self-describing,
which is a big part of their appeal! This no-header fact is also what
explains to me why values have to be not just layout-monomorphic (as you
mention next) but entirely, strictly monomorphic.


(It is, I suppose, part of the model that objects of a given class all have
> a finite, matching layout when accessed by value, even if the details of
> that layout are kept abstract. Which is why value types are monomorphic and
> you need reference types for polymorphism.)
>
> The fact that the VM often discards object headers at runtime is a pure
> optimization.
>
> I'm claiming this picture makes explaining the feature harder,
> unnecessarily. An unhoused value floating around somewhere that I can
> somehow have a reference to strikes me as quite exotic. Tell me it's just
> an object and I feel calmer.
>
>
> Yes, it's just an object. :-)
>
> But not quite how you mean. The new feature here is working with objects
> *directly*, without references. I think one thing you're struggling with is
> that your concept of "object" includes the reference, and if we take that
> away, it doesn't quite seem like an object anymore.
>

Not struggling.

So there is a body of associations our users have with terms like "object",
"class", "primitive", and so on. Many of them are even right (so far). But
they can't all survive intact.

To best serve these users, we have to make a careful determination between
which of those associations we deem are the *essential* ones and which are
merely circumstantial or ancillary. And then we want for the essential
portion to change as little as possible with the release of Valhalla. Users
want to feel lots of stable ground underneath them -- and if it takes a bit
of retraining to show them why it's stable ground, that's still a pretty
good outcome; that is still better than having to tell them "just change
what you think you know to this new thing."

You and I are just advocating for different places to make that cut, that's
all.  I think mine represents more "stable ground", but I accept the burden
of argument here, and will keep working on it.

-- 
Kevin Bourrillion | Java Librarian | Google, Inc. | kevinb at google.com


More information about the valhalla-spec-observers mailing list