The interfaces IdentityObject and ValueObject must die !

Dan Smith daniel.smith at oracle.com
Wed Jan 26 15:42:30 UTC 2022


On Jan 26, 2022, at 2:18 AM, forax at univ-mlv.fr<mailto:forax at univ-mlv.fr> wrote:

In other words: I don't see a use case for distinguishing between primitive and
value classes with different interfaces.

Primitive classes does not allow nulls and are tearable, following your logic, there should be a subclass of ValueObject named PrimitiveObject that reflects that semantics.

But this isn't a property of the *class*, it's a property of the *type*, as used at a particular use site. If you want to know whether an array is flattened, the class of the component can't tell you.

This is especially useful when you have an array of PrimitiveObject, you know that a storing null in an array of PrimitiveObject will always generate a NPE at runtime and that you may have to use either the volatile semantics or a lock when you read/write values from/to the array of PrimitiveObject.

For examples,
 public void m(PrimitiveObject[] array, int index) {
   array[index] = null;  // can be a compile time error
 }

If we said

class Point implements PrimitiveObject

then it would be the case that

Point.ref[] <: PrimitiveObject[]

and so PrimitiveObject[] wouldn't mean what you want it to mean.

We could make a special rule that says primitive types are subtypes of a special interface, even though their class does not implement that interface. But that doesn't really work, either—primitive types are monomorphic. If you've got a variable with an interface type, you've got a reference.

We could also make a special rule that says arrays of primitive types implement an interface PrimitiveArray. More generally, we've considered enhancements to arrays where there are different implementations provided by different classes. That seems plausible, but it's orthogonal to the IdentityObject/ValueObject feature.

Meanwhile, I'd suggest writing the method like this, using universal generics:

<T>  public void m(T[] array, int index) {
   array[index] = null;  // null warning
 }

An impossible type, it's a type that can be declared but no class will ever match.

Examples of impossible types, at declaration site
 interface I extends ValueObject {}
 interface J extends IdentityObject {}
 <T extends I & J> void foo() { }

It would definitely be illegal to declare a class that extends I and J. Our rules about well-formedness for bounds have always been sketchy, but potentially that would be a malformed type variable.

Abandoning the property entirely would be a bigger deal.

If we do not use interfaces, the runtime class of java.lang.Object can be Object, being an identity class or not is a just a bit in the reified class, not a compile time property, there is contamination by inheritance.

Object can't be an identity class, at compile time or run time, because some subclasses of Object are value classes.

What you'd need is a property of individual *objects*, not represented at all with the class. Theoretically possible, but like I said, a pretty big disruption to our current model.

For me, it's like opening the door of your house to an elephant because it has a nice hat and saying you will fix that with scotch-tape each time it touches something.

Ha. This sounds like maybe there's a French idiom involved, but anyway we should try to get John to add this to his repertoire of analogies.



More information about the valhalla-spec-observers mailing list