Final issues regarding records

Remi Forax forax at univ-mlv.fr
Mon Apr 6 11:26:25 UTC 2020


----- Mail original -----
> De: "Gavin Bierman" <gavin.bierman at oracle.com>
> À: "amber-spec-experts" <amber-spec-experts at 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


More information about the amber-spec-experts mailing list