Why can readonly array attributes on a Raku class be modified?

The baz attribute is read only.

The thing is that the baz attribute is an Array which has mutable elements.


When you call $boo.baz you basically get a reference to the array.

Once you have a reference to the array you can do anything that you could normally do to the array.

say $boo.baz.VAR.name; # @!baz

When you assign to an array, what you are really doing is telling the array that it will have new contents.

my @a = ('a','b','c');
say @a.WHICH; # Array|94070988080608

@a = (1, 2, 3);
say @a.WHICH; # Array|94070988080608

Notice that the .WHICH doesn't change. That is because it is still the same array. It just has new contents.

The exact same thing happens when you assign to a public array attribute.
You are not assigning a new array, you are altering the existing one.

All of the behaviours of a variable are not intrinsic to the variable, they are instead handled by an object.
In the case of arrays the object that handles the assignment is Array.


The simplest fix is to just overload the autogenerated accessor method.

class Boo {
    has $.bar;
    has @.baz;

    method baz () { @!baz.List }
}

If you never plan on changing the values in @!baz you could make it a List itself

class Boo {
    has $.bar;
    has @.baz is List;
}