Record canonical constructor is required to be public

forax at forax at
Sun Nov 10 20:42:15 UTC 2019

----- Mail original -----
> De: "Brian Goetz" <brian.goetz at>
> À: "Remi Forax" <forax at>
> Cc: "amber-spec-experts" <amber-spec-experts at>
> Envoyé: Dimanche 10 Novembre 2019 16:36:01
> Objet: Re: Record canonical constructor is required to be public

> Yes, this is about the fourth time you’ve brought this up...

yes, because they have not be a clear answer before.

> I understand your concerns here (as I’ve said before).  We’re not going to do
> anything about it right now — and I don’t want to discuss it further until
> after 14 closes.  But, I will put a few points into the record for when that
> discussion resumes.

I'm ok with that, but i will just point that the fact that you want to delay the discussion about that subject is new to me,
maybe i've missed an email on that subject ?

> I understand that it is a little weird that the constructor is public when the
> class is not.  It is a little weird, but in reality, _it makes no difference_.
> Public doesn’t really mean public, it means “public, subject to the
> public-ness of my containing class, and the exported-ness of my containing
> package.”  So this is really just a personal-preference argument, that you find
> this weirdness more weird than the weirdness introduce by the alternate (and
> more complex) scheme.
> I also understand that you are making a “for consistency” argument with how
> default constructors work.  But, there are more moving parts here, so I don’t
> find the “but default constructors work this way” argument to be compelling in
> this case.
> What you’re missing is the accessors.  A record gains a set of mandated members,
> which must be accessible.  All the talk so far has been about the constructor,
> but it would be ridiculous to use a different accessibility scheme for the
> constructor as for the other mandated members.  We would have to have the same
> treatment for all the mandated members (some of which must be public, as they
> come from Object.)

There are 3 kinds of generated methods, the canonical constructor, accessors and public methods of Object.
Obviously, the later are required to be public.

> And here’s why this scheme is not without cost.  Because the accessors and the
> constructor can be explicitly specified, now we have a more complex rule about
> what accessibilities are allowed on explicit members (i.e., it should be OK to
> upgrade from package to public, but not the other way around).  And this is a
> nontrivial amount of additional spec complexity compared to “they’re always
> public.”  Further, if one has a package-protected record with explicit members,
> and one changes the accessibility of the record, one has to change the
> accessibility of all mandated members.  So while your scheme (assuming it
> encompasses accessors too) may feel cleaner, it is also more expensive for both
> the spec and for the users, who have to internalize a more complex rule.  (Yes,
> its the same as the default constructor, but: _no one knows this rule_, so we
> can’t really lean on the “but its just like something else they understand.”)
> Which is why it is by no means the slam-dunk you seem to think it is, and why
> have been unwilling to reopen this issue.

_no one knows this rule_ is exactly the point of this rule, nobody knows it because it's the right default.
So yes, it maybe more complex in term of spec (one more paragraph ?) but it reduce the cognitive complexity for everybody that will want to provide an explicit canonical constructor (or a compact one) or an explicit accessor for a non top level record. 

> We can reconsider it after the first preview.

no problem with that.


>> On Nov 9, 2019, at 2:31 PM, Remi Forax <forax at> wrote:
>> I  know we already discuss that but i still don't understand why  a canonical
>> constructor has to be public.
>> I understand that a canonical constructor is not a simple constructor because it
>> is also used as a kind of default de-constructor, but this doesn't work well
>> with the current rules for constructors in nested classes/enums and if the
>> class is not visible, it's constructor is not visible anyway.
>> As Brian said in its presentation at Devoxx, records can be used to represent
>> local nominal tuples, like
>>  public void foo() {
>>    record Pair(String name, int value);
>>    ...
>>  }
>> If one want to add a requireNonNull using a compact constructor, it will be
>>  public void foo() {
>>    record Pair(String name, int value) {
>>      public Pair {
>>        Objects.requireNonNull(name);
>>      }
>>    }
>>    ...
>>  }
>> having to declare the constructor to be public in that case seems weird.
>> Mandating that the canonical constructor (hence the compact constructor) to be
>> public:
>> - goes against the idea of encapsulation that a constructor like any members
>> should be the least visible
>> - goes against the rules of default constructors (default constructor use the
>> same visibility as their class) [1]
>> - goes against the rules of constructors in enums (use private or package
>> private depending on the kind of enums) [2]
>> So we a set of rules in the JLS that follows the idea that a constructor should
>> not be public by default in nested classes [1] but the rule for a canonical
>> constructor doesn't follow the same idea [3], this should be fixed.
>> In my opinion, the rule for a canonical constructor should be the same as the
>> rule for a default constructor.
>> regards,
>> Rémi
>> [1]
>> [2]
>> [3]
> >

More information about the amber-spec-experts mailing list