How to remove a multi method in Raku
Asked Answered
B

1

7

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?

Boni answered 12/4, 2020 at 22:30 Comment(0)
P
9

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.

Patin answered 12/4, 2020 at 23:53 Comment(4)
I copied badly, it was actually multi (made many tries). Copying your code in the same file works. But if I augment in an included module, the new multi ((Array:D: Int:D $i where { ... }, *%_)) appears but is not called. Do you know why ?Boni
.... But if I augment a useless AT-POS also in the current file, then the imported multi can be called. It seems that some composition some runtime is missing.Boni
Try adding no precompilation in the module that does the augment.Patin
no precompilation. Well this works ! I wouldn't have find it => Thanks for your awesome answers. You may not see from your side of the cable it but it helps a LOT in this side.Boni

© 2022 - 2024 — McMap. All rights reserved.