Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hello,

I have an application that does this:

use Modern::Perl; use My::Module; use My::Module::Another;

The Module My::Module looks thusly:

use Modern::Perl; use My::Module::Another;

And for the sake of thoroughness there are a few cases inside My::Module::Another that do the following:

My::Module::asub1();

My question to the Monks is as follows: Is there a way to make all of the subroutines in My::Module and My::Module::Another available in the application with just:

use Modern::Perl; use My::Module;

I've written the two modules as follows, they are not OO and they are in separate files.

package My::Module; use Exporter qw(import); @EXPORT = qw(asub1 asub2 asub3); ... 1; package My::Module::Another use Exporter qw(import); @EXPORT = qw(bsub1 bsub2 bsub3); ... 1;

Replies are listed 'Best First'.
Re: Using Modules (updated)
by haukex (Archbishop) on Apr 07, 2017 at 09:44 UTC
    And for the sake of thoroughness there are a few cases inside My::Module::Another that do the following: My::Module::asub1();

    So in package My::Module::Another, do you do use My::Module? Because if not, that's not quite correct - you're relying on My::Module being loaded by someone else, which might not always be true.

    Also, it sounds to me like you might have a circular dependency brewing. Two relatively easy ways to solve that would be to either move the commonly used functions into a third module, or in your case (no OO, and interdependencies between the modules) consider maybe merging the two modules into a single one - unless of course this would cause you to end up with one giant messy file.

    Another important question is whether you can guarantee that the names of the functions exported from the two modules will never collide? If you can, then one simple way to export everything at once would be to import the functions from My::Module::Another into My::Module, and then re-export them from there:

    package My::Module; use Exporter 'import'; use My::Module::Another; our @EXPORT = ( qw/asub1 asub2 asub3/, @My::Module::Another::EXPORT );

    There are other, trickier ways to accomplish the same thing without exporting everything from My::Module::Another into My::Module or vice versa, by writing your own import function. However, this is certainly a more advanced technique, and I would strongly recommend thinking about the above solutions (including whether to merge your modules into one) before going this far. Also, note that I've had to remove support for explicit export lists in this example, since a "merged" list would cause one module to complain since it doesn't know about the other's functions, so this solution isn't without its disadvantages.

    package My::Module::Another; use base 'Exporter'; our @EXPORT = qw/bsub1 bsub2 bsub3/;
    package My::Module; use base 'Exporter'; our @EXPORT = qw/asub1 asub2 asub3/; use My::Module::Another; sub import { warn "WARNING: Ignoring export list!" if @_>1; __PACKAGE__->export_to_level(1, $_[0]); My::Module::Another->export_to_level(1, $_[0]); }

    Lastly, it's also possible to write your own import function and not use Exporter, although this is one of those cases of "do this only if you know what you are doing and why". Also, you lose the functionality of Exporter, such as tags etc. I'm just showing this as a proof-of-concept for completeness, which is why I haven't added support for export lists (Update: added that functionality, note that this assumes there are no duplicate sub names in the modules). I re-use the @EXPORT variable that Exporter uses, but note there is no requirement for this as the variable isn't special - I could also just hard-code the list of functions or use a different variable if I like.

    package My::Module; # no "use Exporter" or "use base 'Exporter'", we're on our own! # ... use Carp; our @EXPORT_FROM_PACKS = qw/ My::Module My::Module::Another /; sub import { my ($class, @export) = @_; my ($callerpack) = caller; my %export = map {$_=>1} @export; for my $frompack (@EXPORT_FROM_PACKS) { # loop over packages # attempt to load that module eval "require $frompack; 1" or croak "failed to load $frompack: $@"; # get their @EXPORT variable my @exps = do { no strict 'refs'; @{"${frompack}::EXPORT"} }; for my $ex (@exps) { # loop over their exports next if @export && !$export{$ex}; no strict 'refs'; # limit scope of "no strict" # target function <-- source function *{"${callerpack}::$ex"} = \&{"${frompack}::$ex"}; } } }

    This is probably a case of "just enough rope to shoot yourself in the foot", but I think it's important to know that what use and Exporter are doing isn't magic, and it is possible to DIY.

    Update 2: Minor tweaks to wording.

Re: Using Modules
by Discipulus (Canon) on Apr 06, 2017 at 19:50 UTC
    Hello, if i understand you can simply put all your sub definitions into My::Module and stop.

    But if you have made two distinct modules perhaps you have some reason to get them separated. If so it looks strange that you have a call inside moduleB that referes to something in moduleA.

    Is My::Module::Another somehow a particular logic subset of My::Module ?

    Anyway when you import subs from a module is no longer needed to call them specifying the full package: asub1 must suffice(instead of a fully qualified My::Module::asub1 )

    I'm not the best advicer on modules design here around but perhaps you can get deeper in your description and in what these modules really represent.

    PS take a look to Proper way to create packages and re-usable code? where some Anonymous like you give some good suggestion about design of modules and separation/aggregation of concerns.

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.