I'm rewriting a framework from Perl5 to Perl6 for my work purposes. At some place I need to collect information from other modules/classes by executing a public sub
they might provide; or they may not. So, it necessary to find out if the sub
is present. This is not a big deal when a module is referenced directly (Foo::<&my-sub>
) or by a symbolic name in a string (&::("Foo")::my-sub). But for the simplicity of it I would like to allow to pass module names as-is (lets say collector
is the method collecting the info):
self.collector( Foo );
Where Foo
could be the following:
module Foo {
use Bar;
use Baz;
our sub my-sub { Bar, 'Baz' }
}
And this is where I'm missing something important from Perl6 syntax because the following:
method collector ( $mod ) {
my $mod-name = $mod.WHO;
my @mods;
with &::($mod-name)::my-sub {
@mods.push: &$_();
}
}
is currently the only way I can perform the task.
I didn't try a type capture yet though. Should work as expected, I guess. So, the question is more about extending my knowelge of the syntax.
The final solution from the exchange with Vadim in the comments on their question. It's arguably insane. They think it's beautiful. And who am I to argue? .oO( Haha, hoho, heehee... )
my $pkg-arg = (Int, 'Int').pick;
my \pkg-sym = $pkg-arg && ::($pkg-arg);
my \sub-ref = &pkg-sym::($subname);
There are two obviously useful ways to refer to a package:
Its symbolic name. Int
is the symbolic name of the Int class.
Its string name. 'Int'
is the string name of the Int class.
Vadim, reasonably enough, wants a solution for both.
In the solution in this answer I simulate the two types of argument by randomly picking one and assigning it to $pkg-arg
:
my $pkg-arg = (Int, 'Int').pick;
Now we need to normalize. If we've got a symbolic name we're good to go. But if it's a string name, we need to turn that into the symbolic name.
Vadim showed a couple ways to do this in the comments on their question. This solution uses a third option:
my \pkg-sym = $pkg-arg && ::($pkg-arg);
If $pkg-arg
is a symbolic name, it'll be False
. With a False
LHS the &&
short-circuits and returns its LHS. If $pkg-arg
is a string name, then the &&
will instead return its RHS, which is ::($pkg-arg)
which is a symbol lookup using $pkg-arg
as a string name.
The upshot is that pkg-sym
ends up containing a package symbolic name (or a Failure
if the lookup failed to find a matching symbolic name).
Which leaves the last line. That looks for a sub named $subname
in the package pkg-sym
:
my \sub-ref = &pkg-sym::($subname);
The &
is needed to ensure the RHS is treated as a reference rather than as an attempt to call a routine. And pkg-sym
has to be a sigilless identifier otherwise the code won't work.
At the end of these three lines of code sub-ref
contains either a Failure
or a reference to the wanted sub.