4

In the code below I have correctly narrowed the type of str to string. However the second += compound operator gives me a compilation error:

ERROR compound assignment not allowed with nullable operands
ERROR operator '+' not defined for 'string?' and 'string'

It looks like the compiler unexpectedly doesn't obey the type narrowing anymore? I'm expecting the type of str to be string until end of the block and I fail to see any problems in my code.

import ballerina/io;

public function main() {
    string? str = "a";
    if str is string {
        str += "b";
        
        // why the second append fails ?
        // ERROR compound assignment not allowed with nullable operands
        // ERROR operator '+' not defined for 'string?' and 'string'
        // str += "c";

        // one possible workaround
        str = <string>str + "c";
    }
    io:println(str);
}

I'm using:

$ bal version
Ballerina 2201.1.0 (Swan Lake Update 1)
Language specification 2022R2
Update Tool 1.3.9
user272735
  • 10,473
  • 9
  • 65
  • 96

1 Answers1

8

This is because type narrowing no longer applies once there is a possibility that the variable may have been assigned to.

For example, it is possible to assign () to str, but thereafter str cannot be of the narrowed type.

    string? str = "a";
    if str is string {
        str = ();

        // Now not valid, `str` is no longer `string`.
        str += "c";
    }

There was a discussion on whether it would be possible to continue to narrow the type if the assignment is with a value belonging to the narrowed type, such as that in the original example. But at the time it was decided not to do this due to reasons discussed in the spec issue.

MaryamZi
  • 871
  • 5
  • 5
  • Ok, I see now. However I'm a bit surprised because I didn't see how `a += "b"` could ever change the type of `a`. Unfortunately I again fail to find any documentation about this detail. In the actual code I think I'm going to hide the unavoidable type test jungle into a function :) – user272735 Jul 19 '22 at 05:16
  • 1
    The ballerina specification explains this. "A narrowed type for a variable x implied by an expression in which x occurs ceases to apply in a region of code where there is a possibility at runtime that x has been assigned to since the evaluation of the expression. It is an error if this results in the type of a variable reference being affected by assignments that lexically follow the variable reference." under conditional type narrowing (https://ballerina.io/spec/lang/2022R2/#conditional_variable_type_narrowing) – lasinicl Jul 22 '22 at 07:33