Implementing AT-POS to return an object instead of a list of things
The AT-POS
method is intended to let an object act as a Positional
object. This is not what you appear to want. You want object[slice]
DWIM.
The best way to achieve that, is to create a postcircumfic:<[ ]>
(multi) candidate for your object:
class A {
method slice(@_) {
say @_; # just to show the principle
}
}
sub postcircumfix:<[ ]>($object, *@indices) {
constant &slicer = &postcircumfix:<[ ]>;
$object ~~ A
?? $object.slice(@indices)
!! slicer($object, @indices)
}
A.new[1,2,4,5]; # [1 2 4 5]
my @a = ^10; # check if foo[] still works
say @a[1,2,4,5]; # (1 2 4 5)
To make sure that the common behaviour of @a[]
is kept, we save the value of the system's postcircumfix:[ ]>
at compile time (with a constant
). Then at runtime, when the object is not of the right class, invoke the original version of postcircumfix:<[ ]>
with the given parameters.
Building on Liz's guidance:
class Names {
has @.names; # Make public so [] can access.
method new (*@names) { nextwith :@names } # Positional .new constructor.
submethod BUILD (:@!names) {} # Called by nextwith'd Mu new.
multi sub postcircumfix:<[ ]> # Overload [] subscript.
( Names $n, $index, *@indices ) # Why `$index, *@indices`?
is default is export # And why `is default`?
{ Names.new: |$n.names[ |$index, |@indices ] } # Why? See my comment
method gist { @!names.join(', ') } # below Liz's answer.
}
import Names;
my $original = Names.new: <jonathan joseph jotaro josuke giorno>;
my $sliced-off = $original[0..2];
say $original.^name; #=> Names
say $original; #=> jonathan, joseph, jotaro, josuke, giorno
say $sliced-off.^name; #=> Names
say $sliced-off; #=> jonathan, joseph, jotaro
PLMK if the code or explanation is inadequate.