Search code examples
traitsraku

Uninstantiable; Callable when using Callable variables from a trait declaration


With this code, I'm trying to add a "logging" trait to a subroutine:

my &loggr = -> $event {
    state %store;
    %store{ DateTime.new( now ) } = $event;
}

multi sub trait_mod:<is>(Sub $s, :$logger){
    loggr( $s.name );
}

multi sub add( Int $a, Int $b) is logger {
    $a + $b;
}

say add(1,2);

However, I get the error:

===SORRY!=== Error while compiling /home/jmerelo/Code/perl6/my-perl6-examples/is-logger-fail.p6
Cannot invoke this object (REPR: Uninstantiable; Callable)
at /home/jmerelo/Code/perl6/my-perl6-examples/is-logger-fail.p6:14

(line 14 would be the line where add is declared). Declaring loggr directly as a sub yields no error. Why am I getting this Uninstantiable error here?


Solution

  • Why am I getting this Uninstantiable error here?

    When used after a my declaration, = (or :=) invokes assignment (or binding) at run-time. A trait applied to a compile-time sub declaration runs at compile-time, which comes first. So your trait calls loggr before it's initialized.

    To fix that, you need to shift the variable initialization to compile-time, eg:

    BEGIN &loggr = ...
    

    or

    constant &loggr = ...
    

    While the error message reads like a low-level error, and it would be nice if it specifically mentioned loggr (but perhaps doesn't because it's low-level), it will hopefully make more sense now:

    ===SORRY!=== Error while compiling ...
    Cannot invoke this object (REPR: Uninstantiable; Callable)
    

    Your code has asked to call loggr at compile-time. But while it does have the appropriate Callable type, it hasn't yet been initialized, so is uninstantiable at the time it is being asked to invoke it.