Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Why can readonly array attributes be modified on a Raku class, but on the other hand, scalars cannot be modified?

How can I make @.baz "readonly"?

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

my $boo = Boo.new;

$boo.baz = (1, 2); # works ... ?
say $boo.baz;

$boo.bar = 1; #fails ... expected

My rakudo version:

This is Rakudo version 2020.05.1 built on MoarVM version 2020.05
implementing Raku 6.d.
like image 916
Julio Avatar asked Sep 23 '20 18:09

Julio


Video Answer


1 Answers

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;
}
like image 75
Brad Gilbert Avatar answered Oct 22 '22 18:10

Brad Gilbert