IdentityObject & abstract superclasses

TheMrMilchmann themrmilchmann at gmail.com
Fri Aug 21 01:12:49 UTC 2020


Hi,

to me, the current issue of how to "declare" inline-friendliness in a
backward-compatible manner seems to be somewhat similar to the introduction
of lambdas to the language.
Since I don't recall seeing this on the mailing list before, I wondered if
you have considered a similar approach.
Note that this is strictly about how to express inline-friendliness of
abstract classes and not about the rules that make an abstract class
inline-friendly.

Let's consider an annotation - I will call it "@__InlineFriendly" for the
sake of this example - that requires the compiler to generate error
messages unless
1) the annotated type is an abstract class, and
2) the annotated type satisfies the requirements to be extensible by inline
classes.

Just like it is done for @FunctionalInterface, the compiler would still
allow abstract classes that satisfy the requirements to be extended by
@__InlineFriendly abstract classes and inline classes.
Probably with an (optional?) compiler warning.

In my opinion, a nice benefit of this approach is that opting into inline
classes (and thus more strict rules for binary-compatibility) becomes an
explicit decision compared to opting into requiring identity by extending
IdentityObject.
Since it aligns more closely with the current defaults (all abstract
classes implicitly require identity since there is no such thing as
no-identity yet), this also seems to be a more natural transition.
E.g. Consider a library with an abstract class A that satisfies the
requirements for inline classes but A is used for locking.

(Unless I'm mistaking) the current conses seems to be that there will be a
point when Java X (with IdentityObject) is released, where locking on A
would become a warning unless A is updated to extend IdentityObject.
Turning this warning into an error (even way down the road) might be tricky
since there is still a chance that older libraries and frameworks contain a
class like A.
When taking the @__InlineFriendly approach, such a breaking error would not
be necessary.
However the possibility that users extend such an object A in an inline
class remains.
Although the risk of that happening accidentally would be greatly reduced
by appropriate compile-time warnings.

A couple of additional open issues and questions:
1. Should it be possible to annotate interfaces with @__InlineFriendly?
This would yield no additional safety as interfaces will always be
inline-friendly, but it might be confusing to disallow it.
2. This approach assumes that "abstract classes always require an identity"
is a good default. While this is consistent with how it has been, it might
not be the best approach going forward. (Though I have to admit that, as a
Java user, I prefer the idea of not changing the default
binary-compatibility rules of abstract classes.)

Thanks for hearing me out. I hope I could contribute something of value to
the discussion. :)


Regards
Leon Linhart

On Tue, Aug 18, 2020 at 1:46 AM Dan Smith <daniel.smith at oracle.com> wrote:

> There's an interesting interaction between IdentityObject and abstract
> superclasses of inline classes that might be worth leaning into.
>
> ---
>
> The "status quo" (inasmuch as one exists):
>
> An inline class can extend a class if it, and all of its supers, 1) are
> abstract, 2) declare no instance fields, and 3) have "empty" <init>
> methods. These properties represent a new kind of abstract class—call it a
> "light" abstract class. Changing a "light" abstract class to be "heavy" is
> a binary incompatible change.
>
> Separately, we have the IdentityObject interface, which is implicitly
> attached to all non-inline concrete classes. An abstract class might also
> be able to implement IdentityObject explicitly, and doing so would also
> disqualify it from being an inline class super.
>
> A struggle in this story is getting programmers to care about whether
> their classes are "heavy" or "light", since even though it's an important
> property, it's easy to overlook (there's no syntax for it, and in many
> cases, there are no immediate effects).
>
> ---
>
> Alternative story:
>
> An inline class must not extend IdentityObject through any of its
> superclasses. (That's it.)
>
> A non-inline class implicitly implements IdentityObject if it 1) is
> concrete, 2) declares an instance field, or 3) has a non-empty <init>
> method. Abstract classes can also explicitly implement IdentityObject.
>
> Changing a class so that it implements IdentityObject is a binary
> incompatible change.
>
> Now we have a highly-visible concept (IdentityObject) that programmers
> should generally be aware of anyway, and they should readily understand a
> difference between abstract classes that implement IdentityObject and those
> that don't.
>
> ---
>
> I think I like the alternative story. It feels simpler.
>
> One reason to avoid it is if we think there's potentially value in a
> "light" abstract class concept that is independent of IdentityObject. For
> example, maybe some other feature could build on the idea of a superclass
> that requires no initialization, without tying that to the topic of object
> identity. I'm having trouble envisioning a use case, though. Another reason
> to avoid it is if we want IdentityObject to be limited to concrete
> classes—no explicit implementing it allowed.
>
> If the alternative story is the one we want, it implies that the "empty
> <init>" JVM feature should be part of Inline Classes, not a separate thing
> we deliver earlier—because it's directly tied to IdentityObject.
>
>


More information about the valhalla-spec-comments mailing list