There is another restriction that doesn't make a lot of sense, an interface can not declare a member record (or a class, an enum, etc) as private.

Yes, I know, and I'd like to eventually clear this one too, it's a gratuitous restriction (though there is a VM component, which makes it more work.)

I deliberately chose not to include this one in this proposed batch, because there was no credible connection to records.   But, the connection to sealed types might be just enough to justify it as part of that project.


This restriction also interacts poorly with sealed interface with implicit permits directive.

  sealed interface I {
    int value();

    private record Impl(int value) implements I { }   // does not compile

    public static I wrap(int value) {
      return new Impl(value);
    }
 }

I propose to relax this restriction as part of Sealed Preview 2.

Rémi



    On 7/27/2020 6:54 AM, Gavin Bierman wrote:

        [Second email of two, looking to close out features we hope to finalize 
in JDK
        16.]


        Records
        -------

        Record classes are a special kind of class that are used primarily to 
define a
        simple aggregate of values.

        Records can be thought of as _nominal tuples_; their declaration 
commits to a
        description of their state and given that their representation, as well 
as all
        of the interesting protocols an object might expose -- construction, 
property
        access, equality, etc -- are derived from that state description.

        Because we can derive everything from a common state description, the
        declaration can be extremely parsimonious. Here is an example of a 
record class
        declaration:

             record Point(int x, int y){}

        The state or, more formally, a record component list, (int x, int y), 
drives the
        implicit declaration of a number of members of the Point class.

        - A `private` field is declared for each record component
        - A `public` accessor method is declared for each record component
        - A constructor is declared with an argument list matching the record 
component
        list, and whose body assigns the fields with the corresponding 
argument. This
        constructor is called the _canonical constructor_.
        - Implementations of the methods: equals, toString and HashCode.

        The body of a record class declaration is often empty, but it can 
contain method
        declarations as usual. Indeed, if it is necessary, the implicitly 
declared
        members - the accessors, canonical constructor, and equals, toString, or
        HashCode methods -- can alternatively be explicitly declared in the 
body.

        Often the reason for explicitly providing a canonical constructor for a 
record
        class is to validate and/or normalize the argument values. To
        enhance the readability of record class declarations, we provide a new 
compact
        form of canonical constructor declaration, where only this
        validation/normalization code is required. Here is an example:

             record Rational(int num, int denom) {
                 Rational {
                     int gcd = gcd(num, denom);
                     num /= gcd;
                     denom /= gcd;
                 }
             }

        The intention of a compact constructor declaration is that only 
validation
        and/or normalization code need be given in the constructor body; the 
remaining
        initialization code is automatically supplied by the compiler. The 
formal
        argument list is not required in a compact constructor declaration as 
it is
        taken from the record component list. In other words, this declaration 
is
        equivalent to the following one that uses the conventional constructor 
form:

             record Rational(int num, int denom) {
                 Rational(int num, int demon) {
                     // Validation/Normalization
                     int gcd = gcd(num, denom);
                     num /= gcd;
                     denom /= gcd;
                     // Initialization
                     this.num = num;
                     this.denom = denom;
                 }
             }

        Once we settled on the design of record classes, things have been 
pretty stable.
        Three issues that did arise were:

        1. Initially canonical constructors were required to be public. This 
was changed
        in the second preview. Now, if the canonical constructor is implicitly 
declared
        then its access modifier is the same as the record class. If it is 
explicitly
        declared then its access modifier must provide at least as much access 
as the
        record class.

        2. We have extended the meaning of the `@Override` annotation to 
include the
        case that the annotated method is an explicitly declared accessor 
method for a
        record component.

        3. To enforce the intended use of compact constructors, we made it a
        compile-time error to assign to any of the instance fields in the 
constructor
        body.

        One area that has generated a number of questions is annotations. Our 
intention
        is that an annotation on a record component is propagated to the field,
        accessor, and/or constructor parameter, according to the applicability 
of the
        annotation. It is not clear what other design choices there are. So we 
hope this
        is just something that has to be learnt, and afterwards it feels 
natural.

        The records JEP also allows for local record declarations. This is 
important as
        records will often be used as containers for intermediate data within 
method
        bodies. Being able to declare these record classes locally is essential 
to stop
        proliferation of classes. We are aware of some small tweaks that will be
        required to the specification during the second preview period, but 
overall this
        feature has not generated any controversy.




Reply via email to