Alternative to IdentityObject & ValueObject interfaces

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Wed Mar 23 10:23:26 UTC 2022


On 22/03/2022 23:56, Dan Smith wrote:
> Other abstract classes and interfaces are fine being neither (thus supporting both kinds of subclasses).

I feel that for such a proposal to be really useful (but that's true for 
the interface-based approach as well IMHO), you need a way for the _use 
site_ to attach an identity vs. value annotation to types that can 
feature both polarities (Object, interfaces, value-compatible abstract 
classes).

It's perfectly fine to have identity vs. non-identity as a declaration 
property, for the cases whether that works. E.g. an ArrayList instance 
will always have identity. An instance of a `value class Point` will 
always be identity-less. Using modifiers vs. marker interfaces here is 
mostly an isomorphic move (and I agree that adding modifiers has less 
impact w.r.t. compatibility).

But it feels like both interfaces and decl-site modifiers fall short of 
having a consistent story for the "neither" case. I feel we'd like 
programmers to be able to say things like:

```
class Foo {
    identity Object lock;

    void runAction(identity Runnable action) { ... }
}
```

So, I believe the modifier idea has better potential than marker 
interfaces, because it scales at the use site in ways that marker 
interfaces can't (unless we allow intersection types in declarations). 
But of course I get that adding a new use-site modifier (like `final`) 
is also not to be taken lightly; aside from grammar conundrums, as you 
say it will have to be tracked by the type system.

Stepping back, you list 4 use cases:

> - Dynamic detection
>
> - Subclass restriction
>
> - Variable types
>
> - Type variable bounds
IMHO, they are not equally important. And once you give up on "variable 
types" (as explained above, I believe this use case is not adequately 
covered by any proposal I've seen), then there's a question of how much 
incremental value the other use cases add. Dynamic detection can be 
added cheaply, fine. I also think that, especially in the context of 
universal generics, we do need a way to say: "this type variable is 
legacy/identity only" - but that can also be done quite cheaply. IMHO, 
restricting subclasses doesn't buy much, if you then don't have an 
adequate way to restrict type declarations at the use sites (for those 
things that cannot be restricted at the declaration), so I'd be also 
tempted to leave that use case alone as YAGNI (by teaching developers 
that synchronizing on Object and interface types is wrong, as we've been 
already trying to do).

P.S.

While writing this, a question came up: let's say I have a generic class 
like this:

```
class IdentityBox<identity T> { ... }
```

Is IdentityBox<Runnable> a well-formed parameterized type? Based on your 
description I'm not sure: Runnable has the "neither" polarity, but T 
expects "identity". With marker interfaces this will just not work. With 
modifiers we could perhaps allow with unchecked warning?

I think it's important that the above type remains legal: I'd expect 
users to mark their type-variables as "identity" in cases where they 
just can't migrate the class implementation to support universal type 
variables. But if that decision results in a source incompatible change 
(w.r.t. existing parameterizations such as IdentityBox<Runnable>), then 
it doesn't look like a great story migration-wise.

Maurizio



More information about the valhalla-spec-observers mailing list