Simplifying 'value' and 'identity'
Remi Forax
forax at univ-mlv.fr
Mon Jan 22 07:54:00 UTC 2024
[resurecting that thread]
----- Original Message -----
> From: "daniel smith" <daniel.smith at oracle.com>
> To: "valhalla-spec-experts" <valhalla-spec-experts at openjdk.java.net>
> Sent: Friday, December 15, 2023 9:22:05 PM
> Subject: Simplifying 'value' and 'identity'
> When we last checked in on it, our story for superclasses/interfaces of value
> classes was as follows:
>
> In general, classes/interfaces are "unconstrained" and support subclassing by
> both value and identity classes. The 'value' and 'identity' keywords act as a
> form of "sealing", restricting subclassing to only classes of the given type.
> Any class/interface that extends classes/interfaces with both keywords is in
> error.
>
> As a special case, concrete classes and some abstract classes with certain
> properties are implicitly 'identity' classes.
>
> This approach has a three-state categorization scheme expressed with two
> keywords ('value', 'identity', and "neither"). This corresponds to two JVM
> flags (ACC_IDENTITY and ACC_VALUE).
>
> I think it holds together fairly well, but it's also somewhat difficult to
> communicate, and not as intuitive as we might like. I find myself periodically
> reminding people (and sometimes myself): "don't forget that there are both
> value abstract classes and unconstrained abstract classes" or "unconstrained
> classes can't have mutable fields, those are only for identity classes".
>
> As we've revised the construction mechanism, we've found ourselves searching for
> an explicit keyword for the third, unconstrained state: "value-capable" or
> "universal" or something. None of these keywords are very compelling, and I
> don't relish the job of trying to get people to adopt these fairly obscure,
> infrequently used terms.
>
> -----
>
> If we're willing to give up some fairly marginal fine-grained controls, this
> story can be simplified significantly.
>
> Concrete classes: nothing new—a concrete class is an identity class by default,
> but may opt out of identity with the 'value' keyword. Concrete value classes
> are implicitly final and subject to a handful of extra constraints.
>
> Abstract classes: an abstract class is also an identity class by default, but
> may use the 'value' modifier to indicate that it doesn't require identity. This
> not the same thing as saying its subclasses *must not* make use of identity,
> it's just an assertion about the abstract class itself (and its supers). Both
> value classes and identity classes may extend an abstract value class. These
> abstract classes are subject to the same constraints as concrete value classes.
>
> Interfaces: all interfaces can be implemented by value classes and identity
> classes. Full stop. If you have a particular need to limit the kinds of
> implementing classes, you can use a sealed interface and provide the
> implementation yourself, or you can make it an informal part of the contract.
> But, like access control, synchronization, and other fine-grained,
> implementation-oriented features, identity is not something interfaces can
> explicitly control.
>
> This approach has a two-state categorization scheme for classes expressed with
> one keyword ('value' and identity). This corresponds to one JVM flag
> (ACC_IDENTITY, for {reasons}). Interfaces have only one state.
>
> What do we lose?
> - You can't force an abstract class/interface to be implemented by *only* value
> classes
> - You can't force an interface to be implemented by *only* identity classes
> - You can't declare an abstract class or interface whose type will refuse to
> support the 'synchronized' keyword
>
> I don't think any of these are enough to justify the extra costs of 3 states or
> an 'identity' keyword. (For awhile, I was considering keeping around the
> 'identity' keyword, just for the purpose of interfaces. But, eh, nobody is
> going to use it.)
Removing the 'identity' keyword is a good things, but i'm not so sure about not allowing users to declare a value interface, because i think that sealing the interface does not convey the right semantics.
The problem is that in the future, a VM may want to flatten a sealed interface (with all its subtypes being value type), currently this is possible on stack but not on heap because '!' can not be used on anything but a value class.
I think we should allow an interface to be prefixed by "value" so
- the compiler adds the interface in the Preload attribute
- '!' is allowed on that interface (in that case all subtypes must be either a value interface or a value class with an implicit constructor)
regards,
Rémi
More information about the valhalla-spec-experts
mailing list