oopmixinsrakuparameterized-constructor

Using role signature in mixins


There seems to be a problem in using the signature given to a role in the roles you want to mix-in. Minimal example:

#!/usr/bin/env perl6

role by-n[$n=1] {
    method multiply(Str $str) { return $str x $n; }
}

role by-string[$n=1] does by-n[$n] {
    method whatever(Str $str) { return $n ~ "→" ~ $.multiply( $str ); }
}

class mighty-þor does by-string[2] {};

say mighty-þor.whatever("*");

This returns an error, which seems to indicate $n has a Mu type:

Cannot resolve caller infix:<x>(Str, Mu); none of these signatures match:
    ()
    ($x)
    ($s, Num:D $n)
    ($s, Any:D $n)
    ($s, Any:U $n)
    (Str:D $s, Int:D $repetition --> Str:D)
    (str $s, int $repetition --> str)
  in method multiply at composable-roles-fail.p6 line 4
  in method whatever at composable-roles-fail.p6 line 8
  in block <unit> at composable-roles-fail.p6 line 13

However, role by-string[$n=1] does by-n[1] or any other number works well. Trying to fix the type in the signature:

role by-n[Int $n=1] {
    method multiply(Str $str) { return $str x $n; }
}

role by-string[Int $n=1] does by-n[$n] {
    method whatever(Str $str) { return $n ~ "→" ~ $.multiply( $str ); }
}

yields a different error:

===SORRY!=== Error while compiling /home/jmerelo/Code/perl6/dev.to-code/perl6/composable-roles-fail.p6
No appropriate parametric role variant available for 'by-n'
at /home/jmerelo/Code/perl6/dev.to-code/perl6/composable-roles-fail.p6:11

While, once again, changing it to role by-string[Int $n=1] does by-n[1] works. Any idea of what's going on here or what can be done to fix this?


Solution

  • My conclusion is that this is a bug, or at least an NYI.

    The problem is that the $n in by-string isn't really set until the role is actually composed into a class. However, the adding of the role by-n happens at compile time of the by-string role. At which time we don't know the value it will get when by-string is composed.

    So, for this to work, we would need to delay the adding of the by-n role to the by-string role until the by-string role is composed. And that's not how it's currently implemented, afaics.

    I'm pretty sure there is a ticket for this already. But to be sure this doesn't fall through the cracks, you should maybe open a GitHub issue.

    Meanwhile, the only way I see around this at the moment, is to copy the methods of the by-n role manually to the by-string role.

    Wish I had better news for you.