简体   繁体   中英

Alternate syntax on introspecting modules/classes/etc

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM