You can easily allow subscript access to your own classes using AT-POS
:
class Foo
{
has @.grid;
method AT-POS($x) is rw { return-rw @!grid[$x] }
method Str { '<' ~ @!grid.join(' ') ~ '>' }
method gist { self.Str }
}
my $foo = Foo.new(:grid(<a b c d e>));
say $foo;
say $foo[2];
$foo[3] = 'z';
say $foo;
output:
<a b c d e>
c
<a b c z e>
But I need two-dimensional subscript access. I've figured out how to make this work for reading, but it dies when writing:
class Bar
{
has @.grid;
method AT-POS($y, $x) is rw { return-rw @!grid[$y;$x] }
method Str { '<' ~ @!grid».join(' ').join("\n ") ~ '>' }
method gist { self.Str }
}
my $bar = Bar.new(:grid(<a b c d e>, <f g h i j>, <k l m n o>));
say $bar;
say $bar[1;2];
$bar[2;3] = 'z';
say $bar;
output:
<a b c d e
f g h i j
k l m n o>
h
Too few positionals passed; expected 3 arguments but got 2
in method AT-POS at ./p6subscript line 25
in block <unit> at ./p6subscript line 33
Is there any way to make this work?
Somehow, the AT-POS
method is not being called. The documentation mentions the use of ASSIGN-POS
instead, so here we go:
class Bar
{
has @.grid is rw;
method AT-POS($y, $x) is rw { say "AT-POS $y, $x"; return-rw @!grid[$y;$x] }
method ASSIGN-POS($y, $x, $new) { say "ASSIGN-POS $y, $x"; @!grid[$y;$x] = $new }
method Str { '<' ~ @!grid».join(' ').join("\n ") ~ '>' }
method gist { self.Str }
}
my $bar = Bar.new(:grid(<a b c d e>, <f g h i j>, <k l m n o>));
say $bar;
say $bar[1;2];
$bar[2;3] = 'z';
say $bar;
Which, interestingly, yields another error:
Cannot modify an immutable List ((k l m n o))
in method ASSIGN-POS at semilist-so.p6 line 8
in block <unit> at semilist-so.p6 line 16
So the problem is not really the syntax, but the fact that you are working with immutable lists. You should use Array
s, which are mutable, and you'll be able to do that.
class Bar
{
has @.grid is rw;
method AT-POS($y, $x) is rw { return-rw @!grid[$y;$x] }
method ASSIGN-POS($y, $x, $new) { @!grid[$y;$x] = $new }
method Str { '<' ~ @!grid».join(' ').join("\n ") ~ '>' }
method gist { self.Str }
}
my $bar = Bar.new(:grid([<a b c d e>], [<f g h i j>], [<k l m n o>]));
say $bar;
say $bar[1;2];
$bar[2;3] = 'z';
say $bar;
My solution would be (provided we only have 2 dimensions):
class Bar {
has @.grid;
method TWEAK() { $_ .= Array for @!grid }
method AT-POS(|c) is raw { @!grid.AT-POS(|c) }
method Str { '<' ~ @!grid».join(' ').join("\n ") ~ '>' }
method gist { self.Str }
}
The TWEAK
will convert any lists that were given to arrays if they're not already. The is raw
on AT-POS
is all that is needed: return-rw
is a very roundabout way of doing that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With