How can I augment a class with a multi-method that will be called before the already defined one ?
I am trying to enable negative subscript: @arr[-1]
like in this article but without changing the source.
So I augment Array with:
augment class Array {
proto method AT-POS(Array:D: Int:D $i where <0 ) {
say "AT-POS called";
my $pos = -1;
my $ix = $pos + self.elems;
return self.AT-POS($ix);
}
};
But as stated in the doc
Please note that adding a multi candidate that differs only
in its named parameters will add that candidate behind the already defined one
and as such it won't be picked by the dispatcher.
So my multi is never called:
say .signature for @arr.^method_table{'AT-POS'}.candidates ;
(Any:U \SELF: int \pos, *%_)
(Any:U \SELF: Int:D \pos, *%_)
(Any:U: Num:D \pos, *%_)
(Any:U: Any:D \pos, *%_)
(Any:D: int \pos, *%_)
(Any:D: Int:D \pos, *%_)
(Any:D: Num:D \pos, *%_)
(Any:D: Any:D \pos, *%_)
($: Any:U \pos, *%_)
(Any:D: \one, \two, *%_)
(Any:D: \one, \two, \three, *%_)
(Any:D: **@indices, *%_)
(List:D: int $pos, *%_)
(List:D: Int:D $pos, *%_)
(Array:D: int $pos, *%_)
(Array:D: Int:D $pos, *%_) # Their
(Array: $a, *%_)
(Array:D: Int:D $pos, *%_) # My
I want my method to be called before their. How can can I modify the dispatcher?
Named parameters don't come into the matter; there aren't any here. The problem is that instead of adding a multi
candidate that is more specific, the code in the question instead tries to replace the proto
. If instead a multi
candidate is added like this:
use MONKEY-TYPING;
augment class Array {
multi method AT-POS(Array:D: Int:D $i where $i < 0) {
nextwith($i + self.elems)
}
}
Then, due to the presence of the where
clause, it will be considered before the usual AT-POS
candidate without one. Since the standard candidate still applies too, nextwith
can be used to defer to it. Using the above augment
, the program:
my @arr = 1, 2, 3;
my $idx = -1;
say @arr[$idx];
Will output 3
.
The usual caveats about augment
apply, and since every array index operation will pay this cost, expect a significant slowdown.