ballerinaballerina-swan-lake

Clarification on type inclusions in record in Ballerina


I have defined records like this:

type Record1 record {|
    int a;
    string b;
    string...;
|};


type Record2 record {|
    boolean c;
    string[] d;
    int...;
|};

type Record record {
    *Record2;
    *Record1;
};

How does the type inclusions work here?

When I make the record close like this:

type Record record {|
    *Record2;
    *Record1;
|};

Then it shows an error as expected: cannot use type inclusion with more than one open record with different rest descriptor types

But when I do something like this then the error is gone:

type Record record {|
    *Record2;
    *Record1;
    float...;
|};

In this case there should be an error right? Or am I missing something

I tried to refer to the spec here: https://ballerina.io/spec/lang/master/#section_5.4.2.2. But I could not understand the overriding part.
Appreciate any input on this


Solution

  • Inclusion includes the rest descriptor also. So it results in a conflict when you do

    type Record record {|
        *Record2;
        *Record1;
    |};
    

    since the compiler cannot identify the rest descriptor to use. Note that this is not a closed record.

    For example, if there was no conflict, you could add rest fields to Record.

    type Record1 record {|
        int a;
        string b;
        int...; // changed to int
    |};
    
    type Record2 record {|
        boolean c;
        string[] d;
        int...;
    |};
    
    type Record record {|
        *Record2;
        *Record1;
    |};
    
    Record r = {
        a: 0,
        b: "",
        c: false,
        d: [],
        "e": 1 // allowed since the rest descriptor is int
    };
    

    If you want to make it closed, you can use never...;.

    type Record record {|
        *Record2;
        *Record1;
        never...;
    |};
    

    Inclusion of these types also works when you use an inclusive record typedesc

    type Record1 record {|
        int a;
        string b;
        string...;
    |};
    
    type Record2 record {|
        boolean c;
        string[] d;
        int...;
    |};
    
    type Record record {
        *Record2;
        *Record1;
    };
    

    because this is equivalent to

    type Record record {|
        *Record2;
        *Record1;
        anydata...;
    |};