Search code examples
javaarityjava-recordjava-16

Why is the variable arity record component not inferred with custom constructor?


Trying out some code with record and record components. I was making use of the variable rarity components and was struck with a compile-time error over a custom constructor.

public record Break<R extends Record>(R record, String... notifications) {

    public Break(R record, String... notifications) {
        System.out.println("record: " + record + " and notifications: " + Arrays.toString(notifications));
        this.record = record;
        this.notifications = notifications;
    }

    // compile error: non canonical record constructor must delegate to another costructor
    public Break(R record) { 
        System.out.println("record: " + record);
        this.record = record;
    }

    public Break() {
        this(null); // this works 
        // actually intelliJ suggests it uses the constructor that is not compiling
    }


    public static void main(String[] args) {
        new Break<>(new Break<>());
    }
}

What I am curious to understand is, how is the similar constructor inferred when invoked via another custom constructor without any components provided for initialization.


Solution

  • This has nothing to do with variable arity. All record constructor chains must "bottom out" in the canonical constructor (which may be specified using the compact form), variable arity or not. This manifests as a requirement that each non-canonical constructor must delegate to another constructor; eventually this means chains bottom out in at the canonical.

    You can fix your bad constructor with:

    public Break(R record) {
        this(record);
    }
    

    But, you don't even need to declare this constructor all, since the canonical constructor can handle calls of the form new Break(r) already.