rakunqp

How to remove a multi method in Raku


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?


Solution

  • 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.