http://qs321.pair.com?node_id=372477

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

Fellow monks, I have a puzzlement... I'm trying to figure out how to re-export subs from one module into another. What's particularly puzzling is that, while I can come up with a version that works (although it's a bit kludgey-er than I'd like), when I swap to use base, it doesn't.

Here's what I've got that works:

### External.pm package External; use strict; use base qw(Exporter); use vars qw(@EXPORT); @EXPORT = qw(external); sub external { print "I'm in the external package!\n"; } 1; ### Foo.pm package Foo; use strict; use External; use base qw(Exporter); use vars qw(@EXPORT); push @EXPORT, @External::EXPORT; sub from_base { print "In base...\n"; external(); print "Done in base...\n"; } 1; ### Bar.pm package Bar; use strict; use Foo; use vars qw(@ISA); @ISA = qw(Foo); #use base qw(Foo); my $x = bless { }, 'Bar'; $x->from_base(); external(); 1; ### base-tester #!/usr/bin/perl -w use strict; use Bar; print "Done\n";

With the above bits, I get the correct behavior - which is to say that I can access external() from Bar.pm. However, if I comment out the lines for use Foo;, use vars..., and @ISA... and uncomment use base qw(Foo);, it breaks.

tye had suggested looking into Exporter's export_to_level() or re-calling import, except the idea is to, ideally, need the fewest moving parts in Foo.pm (and none at all in Bar.pm).

And, yes, I'm aware of Spiffy, but I'd prefer something that's a little lighter-weight.

Thoughts, comments, suggestions?

Replies are listed 'Best First'.
Re: Mixing @EXPORT and use base
by chromatic (Archbishop) on Jul 07, 2004 at 18:52 UTC

    base doesn't call import(); it exists to help with subclassing, not procedural module loading. Either stick with use or call import() yourself.

      Ah-ha... The lightbulb finally went on...

      This is the first time I've really needed to delve into the import / export mechanism, so this has definitely been uncharted territory for me.

      I've now got a working version that includes pushing External's @EXPORT and just a use base / import in Bar. It's not as absolutely clean as I'd like, but I suspect it's probably as good as I'm going to get.

Re: Mixing @EXPORT and use base
by Joost (Canon) on Jul 07, 2004 at 18:03 UTC
    And, yes, I'm aware of Spiffy, but I'd prefer something that's a little lighter-weight.
    Smells at the Spiffy docs... Oh my... Brian Ingerson has finally gone completely mad!
    You can also use the traditional use base 'MySpiffyBaseModule'; syntax and everything will work exactly the same. The only caveat is that Spiffy.pm must already be loaded. That's because Spiffy rewires base.pm on the fly to do all the Spiffy magics.
    I don't think the semantics you want are easy to achieve, and might trip up other modules in the process. Also, I'm curious why you don't use class methods and inheritance. It might look more complicated, but if you store the classname in a varible, it tends to be pretty short anyway.

    example:

    my $f = 'Foo'; $f->external();
    Only 1 character more...

    If I'm missing something here, please tell me.

    J.

      The problem with $f->external() is that it adds to the argument list being passed to external().

      Ideally, I don't need to (nor want to) make external() smarter about whether it's being called as a class method or just an exported subroutine.

Re: Mixing @EXPORT and use base (simple)
by tye (Sage) on Jul 07, 2004 at 20:19 UTC

    I don't see how

    sub Foo::import { External->export_to_level( 2, @_ ) }

    is a lot of moving parts.

    - tye        

      Well... Ok. "Moving parts" was a misnomer, but export_to_level doesn't solve the issue of use base. The other two bits that make me uncomfortable are that the "2" is a bit of a magic number (and doesn't allow for further "inheritance" of the exports) and I'd need to do that explicitly for every module that needs to generate exports.

      By just altering @EXPORT in the base and putting an explicit import in the derived class, I get exactly the same behavior.