[External] : Re: Consolidating the user model

Dan Smith daniel.smith at oracle.com
Wed Nov 3 23:05:52 UTC 2021


On Nov 3, 2021, at 3:40 PM, Kevin Bourrillion <kevinb at google.com<mailto:kevinb at google.com>> wrote:

The problem is that you want to say that the Point gets converted to some other thing, yet that other thing:
- is == to the original

I would hope that's already true of int==Integer?

Formally, you can't literally compare an int with an Integer. All comparisons between a boxed Integer and an int have to decide if they're primitive comparisons, reference comparisons, or illegal, based on some rather complex conversions and disambiguation rules. At runtime, if the types you use result in a reference comparison, the answer depends on quirks of the interning logic.

Informally, whatever path you take, where boxed Integers are involved, == is unreliable, because you may indeed be comparing two different objects that happen to have been derived from the same number.

Now, if we kept `int` and `Integer` as distinct things, but turned `Integer` into an identity-free class, I suppose it's true that you wouldn't be able to tell whether two boxes were distinct or not, because == would always be true. (More properly, "are these distinct boxes with the same payload?" would be a malformed question to ask, because it presumes identity.)

So, okay: to be fair to these reimagined boxes, I'll stipulate that they are identity-free, and thus indistinguishable with ==.

- 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"?

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.

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.

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!");
}

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. 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.

(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.



More information about the valhalla-spec-observers mailing list