> From: "Brian Goetz" <brian.go...@oracle.com> > To: "Dan Heidinga" <heidi...@redhat.com> > Cc: "Remi Forax" <fo...@univ-mlv.fr>, "Kevin Bourrillion" <kev...@google.com>, > "daniel smith" <daniel.sm...@oracle.com>, "valhalla-spec-experts" > <valhalla-spec-experts@openjdk.java.net> > Sent: Vendredi 19 Novembre 2021 14:32:38 > Subject: Re: [External] : Re: EG meeting, 2021-11-17
> The translation model I had in mind was more complicated, but my point was > that > the reason we disallow inheritance is because we’re trying to disallow layout > polymorphism for concrete types, so that we know exactly how big a “C” is. And > this is not inconsistent with abstract superclasses contributing fields. > There’s definitely translational complexity, but its not insurmountable. I > raised it because Kevin seemed to be going somewhere with extension, and I > wanted to get a better sense of what that was. I have definitely wished for > abstract records a few times before, and I could imagine Kevin has similar use > cases in mind. For records, it's easy to avoid abstract inheritance because all states are public, so instead of abstract A { int a; } abstract B extends A { int b; } record C() extends B { } one can write interface A { int a(); } interface B extends A { int b(); } record C(int a, int b) implements B { } Rémi >> The model requires fields in value types to be final so each of those >> fields should be marked as `final` to ensure they show the right >> properties to users via reflection. Additionally, that means that A & >> B would need to have constructors to set those final fields to be >> consistent with the rest of the language, but C will never run those >> constructors. >> Without a constructor, there's no place for A & B to set invariants on >> their fields. If they can't define the contract for those fields, >> then they shouldn't define the fields. This is similar to how >> interfaces work: the interface can define a "int getX()" method that >> implementers have to implement, but it can't define the "int x" field >> directly. >> If we relaxed the "must be final" field constraint, we'd need some >> other rule to prevent A or B from defining a setter for their fields >> as there is no single set of bytecode that can implement a setter for >> both a value and an identity class: >> void setA(int a) { putfield A.a } >> vs >> A setA(int a) { withfield A.a; areturn; } >> Note in particular that the second *must* return a new A as values are >> immutable. >> The details around this would be hard for users to keep straight and >> would be easy to violate when refactoring as the authors of A & B >> would need to know that their subclasses include value types. And >> this would be incredibly hard to keep straight across maintenance >> boundaries. >> --Dan >>> On Nov 18, 2021, at 5:58 PM, Remi Forax < [ mailto:fo...@univ-mlv.fr | >>> fo...@univ-mlv.fr ] > wrote: >>> ________________________________ >>> From: "Brian Goetz" < [ mailto:brian.go...@oracle.com | >>> brian.go...@oracle.com ] >>> > >>> To: "Kevin Bourrillion" < [ mailto:kev...@google.com | kev...@google.com ] > >>> Cc: "Dan Heidinga" < [ mailto:heidi...@redhat.com | heidi...@redhat.com ] >, >>> "daniel smith" < [ mailto:daniel.sm...@oracle.com | daniel.sm...@oracle.com >>> ] >>> >, "valhalla-spec-experts" < [ >>> >mailto:valhalla-spec-experts@openjdk.java.net | >>> valhalla-spec-experts@openjdk.java.net ] > >>> Sent: Jeudi 18 Novembre 2021 23:34:51 >>> Subject: Re: EG meeting, 2021-11-17 >>> I think it is reasonable to consider allowing bucket two classes to be >>> abstract. >>> They could be extended by other classes which would either be abstract or >>> final. The intermediate types are polymorphic but the terminal type is >>> monomorphic. >>> A similar argument works for records. >>> I suppose you are talking about empty (no field) abstract classes. >>> We need that for j.l.Object, j.l.Number or j.l.Record. >>> From a user POV, it's not very different from an interface with default >>> methods. >>> Rémi >>> Sent from my iPad >>> On Nov 18, 2021, at 5:27 PM, Kevin Bourrillion < [ mailto:kev...@google.com >>> | >>> kev...@google.com ] > wrote: >>> On Wed, Nov 17, 2021 at 7:05 PM Dan Heidinga < [ mailto:heidi...@redhat.com >>> | >>> heidi...@redhat.com ] > wrote: >>>> Let me turn the question around: What do we gain by allowing >>>> subclassing of B2 classes? >>> I'm not claiming it's much. I'm just coming into this from a different >>> direction. >>> In my experience most immutable (or stateless) classes have no real >>> interest in >>> exposing identity, but just get defaulted into it. Any dependency on the >>> distinction between one instance and another that equals() it would be a >>> probable bug. >>> When B2 exists I see myself advocating that a developer's first instinct >>> should >>> be to make new classes in B2 except when they need something from B1 like >>> mutability (and perhaps subclassability belongs in this list too!). As far >>> as I >>> can tell, this makes sense whether there are even any performance benefits >>> at >>> all, and the performance benefits just make it a lot more motivating to do >>> what >>> is already probably technically best anyway. >>> Now, if subclassability legitimately belongs in that list of >>> B1-forcing-factors, >>> that'll be fine, I just hadn't fully thought it through and was implicitly >>> treating it like an open question, which probably made my initial question >>> in >>> this subthread confusing. >>> -- >>> Kevin Bourrillion | Java Librarian | Google, Inc. | [ >>> mailto:kev...@google.com | >>> kev...@google.com ]