[records] customized accessor returning subtype

Remi Forax forax at univ-mlv.fr
Tue Dec 10 01:06:07 UTC 2019


----- Mail original -----
> De: "Alex Buckley" <alex.buckley at oracle.com>
> À: "amber-dev" <amber-dev at openjdk.java.net>
> Envoyé: Mardi 10 Décembre 2019 01:36:40
> Objet: Re: [records] customized accessor returning subtype

> I'm glad this was asked and answered during CSR, but I think Dmitry is
> clear about WHAT the spec says. I believe he is asking WHY an explicit
> accessor's return type must be identical to the component's type.
> 
> At the heart of the matter is the fact that a Number-typed component
> implies a Number-typed field. Code in an accessor with an Integer return
> type would have to downcast the field often, or at least sometimes.
> Everything about that accessor makes it harder to understand the state
> of the record *which was meant to be plain from the Number component*.
> Does the "true" state involve a Number or an Integer, and does it depend
> on other conditions, and when, and why? A covariant override is for when
> a subclass adds specialization, but there's no specialization to be
> gained within a record.

Yes, you can not create two accessors, one overriding the other inside the same class so there is little point to have a record supporting that.
It will be become a corner case for an IDE that want to refactor a record to a class or vice versa.

What you can do is the opposite, if you have an interface with an abstract accessor returning a super type,
then a record can implement it:

  public interface Namable {
    Object name();
  }
  
  public record Foo(String name) implements Namable {
  }

in that case, you will correctly get a bridge like this:
  public java.lang.String name();
    descriptor: ()Ljava/lang/String;
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #16                 // Field name:Ljava/lang/String;
         4: areturn

  public java.lang.Object name();
    descriptor: ()Ljava/lang/Object;
    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokevirtual #13                 // Method name:()Ljava/lang/String;
         4: areturn


> 
> Alex

Rémi

> 
> On 12/9/2019 4:04 PM, Joe Darcy wrote:
>> FYI, this issue was raised in the CSR review:
>> 
>>> In "An implicitly declared public accessor method with the same name
>>> as the record component, whose return type is the declared type of the
>>> record component, unless a public method with the same signature is
>>> explicitly declared in the body of the declaration of R."
>>>
>>> does that imply a "covariant override" accessor can be explicitly
>>> defined as the signature does not include the return type? For example
>>> if the component had a type of Object and the user defined an
>>> accesssor method with a type of String? Would a bridge method need to
>>> be defined? Should the return type be constrained to match too?
>>>
>> 
>> https://bugs.openjdk.java.net/browse/JDK-8233433?focusedCommentId=14302123&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-14302123
>> 
>> 
>> and replied to
>> 
>>> This is a very good question. I've actually changed the description of
>>> accessor methods and constructor methods to make this clearer (I
>>> hope). In essence there is a two stage process. For accessor methods:
>>> If you have the name of a component and an empty formal parameter
>>> list, then you are considered to be an accessor method for the
>>> component. We then ask additional criteria of you - it's a
>>> compile-time error if you don't satisfy them! This includes having a
>>> return type that is identical to the derived type of the record
>>> component, being |public|, etc. It's essentially the same for
>>> constructors: a record component list essentially derives a canonical
>>> constructor signature. If you are a constructor that is
>>> override-equivalent, then you are a canonical constructor. We then ask
>>> additional criteria of you, being |public|, not being generic, etc.
>>>
>>> These definitions clear up a lot of corner cases, and more importantly
>>> lead to better error messages. (In your particular example, the
>>> |String| returning method would /not/ be an accessor for the |Object|
>>> component, so one would be implicitly declared for you, and then you'd
>>> get an error as we'd have two overloads with identical signatures).
>>>
>> https://bugs.openjdk.java.net/browse/JDK-8233433?focusedCommentId=14302457&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-14302457
>> 
>> 
>> Cheers,
>> 
>> -Joe
>> 
>> On 12/9/2019 11:09 AM, Dmitry Bessonov wrote:
>>> Is there any reason for not allowing a customized accessor to return
>>> rc subtype:
>>>
>>> record R(Number number) {
>>>      public Integer number() {
>>>          return 42;
>>>      }
>>> }
>>>
>>> Error: java: invalid accessor method in record R
>>>    (return type of accessor method number() is not compatible with
>>> type of record component number)
>>>
>>>
>>> dmitry


More information about the amber-dev mailing list