EG meeting, 2021-11-17

Dan Heidinga heidinga at redhat.com
Mon Nov 22 19:09:43 UTC 2021


> This is the second turn of the crank (the first was "you can extend Object only"), but as this conversation hinted, there may be a further turn where abstract identity-agnostic classes can contribute to the layout and initialization of a concrete final by-value class without pulling it into the world of new-dup-init.  The following is an exploration, not a proposal, but might help find the next turn of the crank.  The exposition is translational-centric but that's not essential.
>
> An abstract class can contribute fields, initialization of those fields, and behavior.  We can transform:
>
>     abstract class C extends ValueObject {  // no identity children, please
>         T t;
>
>         C(T t) { ... t = e ... }
>     }
>
> into
>
>     interface C {
>         abstract <V extends C> protected V withT(V v, T t);
>         abstract protected T t();
>
>         static<V extends C>  protected V init(V v, T t) {
>            ... v = withT(v, e) ...
>           return v;
>        }
>     }
>
> and a subclass
>
>     b2-class V extends C {
>         U u;
>
>         V(T t, U u) { super(t); u = e; }
>     }
>
> into
>
>     b2-class V implements C {
>         T t;   // pull down fields from super
>         U u;
>
>         V(T t, U u) {
>             V this = initialvalue;
>             this = C.init(this, t);
>             this = this withfield[u] u;
>         }
>     }
>
> The point of this exercise is to observe that the two components of C that are doing double-duty as both API points for clients of C and extension points for subclasses of C -- the constructor and the layout -- can be given new implementations for the by-value world, that is consistent with the inheritance semantics the user expects.
>
> Again, not making a proposal here, as much as probing at the bounds of a new object model.
>
> (I think this is similar to what you sketched in your next mail.)

I spent some time playing with this model and it seems pretty workable
in a consistently compiled world, though with some pretty sharp edges.
Outside such a world - where classes may be recompiled separately - it
would be easy to break compatibility as the translation copies
implementation details of the super into both field and constructor
signatures.

Changing C->C' in otherwise compatible ways such as adding a field, or
changing the type of the field (depending on accessibility) would lead
to many more ICCE cases then we see today and be a surprise to users.

As an EG, we've consistently walked back the design anytime the
translation strategy has become too clever, or resulted in classfile
artifacts saying something different than the source, or changed the
meaning of the source (e.g. Class::isInterface).  This feels like
we're starting to fall down the clever rabbit hole and reminds me of
Paul Phillips "Scala war stories" JVMLS talk which highlighted the
compatibility issues scala has faced due to their clever translation
strategy.

And some of this seems like ground we've already trod (and rejected).
Brian, to quote one of your emails from Dec 2019 [1] on this topic:

> (I remain unconvinced that instance fields in inline-friendly abstract
> classes could possibly be in balance, cost-benefit-wise, and
> super-unconvinced about inlines extending non-abstract classes.)

I'm trying to understand what flipped the cost-benefit calculation
here that makes it worthwhile to re-explore allowing values to inherit
fields from abstract supers.

--Dan

[1] https://mail.openjdk.java.net/pipermail/valhalla-spec-experts/2019-December/001181.html



More information about the valhalla-spec-experts mailing list