----- Mail original ----- > De: "Gavin Bierman" <gavin.bier...@oracle.com> > À: "amber-spec-experts" <amber-spec-experts@openjdk.java.net> > Envoyé: Lundi 6 Avril 2020 12:10:55 > Objet: Final issues regarding records
> Dear Experts: > > I’d like to circle back on a couple of issues regarding records. I am > finalizing > the draft language spec - would really like to complete this very soon - so it > would be great to get some EG feedback so we cancomplete the spec (and tweak > the implementation as necessary). I'm especially keen to hear from anyone who > has actually been playing with the records prototype already. > > > #1. Accessibility of various record members. > > In an earlier email, I wrote: > >> Currently the mandated members are public regardless of the accessibility of >> the record type. What should be the default accessibility for record >> members? >> >> A: Currently the most popular proposal is that mandated members get >> accessibility of the record type. Other members get package level >> accessibility as per a regular class. (Note: it should be legal for explicit >> declarations of mandated members to specify something _more_ accessible >> (same rules as overriding.) ) > > Just to clarify which members we are talking about; there are actually two > categories to consider: > > 1. The implicitly declared accessor methods corresponding to the record > components. > > 2. The canonical constructor (including possibly a compact constructor). > > For these members, the current spec and implementation require that they are > `public` regardless of the accessibility of the enclosing record type. > > The question before the house is whether this is the right design. A gut > reaction is that it feels wrong; why insist on a public accessibility > regardless > of the enclosing declaration? But after a little thought, it is not so clear > that this is the wrong design. > > First, note that enums already have this implicit-members-are-`public` > feature - > the implicitly declared `values` and `valueOf` methods are `public` regardless > of the accessibility of the enum type. As far as I am aware, this feature of > enums has not caused any confusion (or much comment). > > Second, consider the case where we are using interfaces to specify the > behavior > of the record type, including the accessor methods. For example: > > interface I { > int i(); > } > > record R(int i) implements I {} > > If we make R private, then there is no way we can satisfy our contract as > interfaces can’t have private methods. In this example, there’s not a lot we > can > do other than explicitly declare the accessor method ourselves. This is a > shame > - we can't utilize the implicit declaration of accessor methods because of a > mismatch of accessibility. > > Whilst this example is a little contrived, it asks whether the essence of the > (public) contract that records satisfy, even private ones, is that they > support > accessor methods to access the values of the record components. > > Regarding the canonical constructor: it's indeed the case that for normal > class > declarations the *default* constructor gets the access modifier from the > enclosing class declaration. But, this is a weak argument for *canonical* > constructors, which are different in a number of ways already. > > I can see 4 options: > > 1. Keep the everything public option as currently spec-ed and implemented. > This > is simple to remember, and not without precedent. > > 2. Change the current spec and implementation so the accessor methods and > canonical constructor inherit the accessibility from the record type. This is > also simple to remember, but it ignores the issues with interfaces detailed > above. > > 3. Incorporate both strategies: Perhaps that the canonical constructor > inherits > accessibility from the record type, whereas accessor methods are required to > be > public. > > 4. Some variant of (2) that can deal with the interface example (?) > > What are your thoughts? 1/ We have carefully to provide a path to refactor an existing class to a record, so a record constructor and a class mandated constructor so should have the same accessibility. In the following code, the class R should be able to be refactored to a record R. class A { private class R {} private record R() {} } 2/ I don't understand how a non public accessor can be useful, if the class has non public access, it can use the fields instead of the accessor, so i fail to see a use case for non public accessors. Given 1/ and 2/, the corresponding option is (3). > > > #2. Annotating explicit accessor methods > >> Q10. Special annotation for explicit declaration of accessors. >> >> Tagir [6] proposes a new `@RecordAccessor` annotation to mark explicit >> accessors, much as `@Override` is used to mark method overrides. >> >> A: Rather than introduce a new accessor, we will consider extending the >> meaning of the `@Override` annotation to include this case. > > There's been some discussion about this, but we were hoping for more! The > motivation for co-opting @Override is that its purpose already is to allow the > compiler to give us better type checking because we’ve captured a bit of user > intent, so this feels similar. However, Peter has made the excellent point > that > extending `@Override` in this way might be confusing in record declarations > that > also contain implementations of methods from interfaces. > > Essentially, I think our options are: > > 1. Do nothing. (We can come back to this at the next release.) > > 2. Co-op `@Override` > > 3. Invent a new annotation, as suggested by Tagir. Co-op @Overrride. > > > Any further thoughts ? > > > --- > > Thanks for your consideration. I look forward to hearing your feedback. regards, Rémi > > Best wishes, > Gavin