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