Search code examples
perlstacksubroutine

How to stack function definitions in perl (call them all at once)?


So I want something like:

module0.pl

sub fun {
    print "fun $_[0] from 0\n"
}

1

module1.pl

sub fun {
    print "fun $_[0] from 1\n"
}

1

main.pl

BEGIN{push @INC, "."};

require "module0.pl";
require "module1.pl";

fun("test")

Which will print (in any order - I don't care) :

fun test from 0
fun test from 1

Is it possible - and what is the most elegant syntax to do it?


Solution

  • So you want to call a list of subs from various packages (here equally named) ?

    One way, using normal packages

    package Pack1;
    
    use warnings;
    use strict;
    use feature 'say';
    
    sub fun { say "fun $_[0] from ", __PACKAGE__ }
    
    1;
    

    The calling program, in the same directory with this package (and its counterpart Pack2)

    use warnings;
    use strict;
    use feature 'say';
    
    use FindBin qw($RealBin);
    use lib $RealBin;
    
    use Pack1;
    use Pack2;
    
    for my $packname (qw(Pack1 Pack2)) { 
        MAKENAME: {
            no strict 'refs';
            my $fun_name = $packname . '::' . 'fun';
            $fun_name->("hi") if exists &{$fun_name};
        }   
    }
    

    I put that scoped no strict 'refs' in another block, and name the block, just so; if this is all that is done in the loop there is no need to introduce another scope. We need the refs stricture off for using it as a subroutine reference but then it makes sense to scope the name itself as well.

    A few notes

    • I don't know why those are .pl files which are require-ed; they should be packages and I wrote them that way. Let me know if there is actually a specific (and unbeatable) reason for them to be require-ed programs

    • Add directories to @INC using the lib pragma with $FindBin::RealBin, not by hacking @INC


    Or copy the coderef

    for my $packname (qw(Pack1 Pack2)) {
        my $fun = \&{ $packname . '::' . 'fun' };
    
        $fun->('hi');
    }
    

    But if we do need to check for existence that should rather be

    for my $packname (qw(Pack1 Pack2)) {
    
        my $fun_name = $packname . '::' . 'fun';
        next if not exists &{$fun_name};
    
        my $fun = \&{$fun_name};
    
        $fun->('hi');
    }