I know this must be frustrating, but once you do it a couple times, it will seem natural. Let me break it down a bit.

First, a use statement really does something like this behind the scenes:

# use Module @LIST is really: BEGIN { require Module; Module->import( @LIST ); }

The require call will load a library file just like do, but only if it hasn't already been loaded. The call to the import method only happens if it is defined in the Module namespace (or is inherited).

So what if you don't have a package statement (and I'm leaving off strict, warnings and Exporter for space and clarity for the moment):

# Bozo.pm sub go_bozo { return "BOZO!\n" } 1;

The first time you use Bozo, two things happen. First, Bozo.pm is loaded just like do. That means that go_bozo is compiled into the current package. For example:

# script.pl package Burble; use Bozo; package main; print Burble::go_bozo();

The second thing that happens it that Perl looks to see if it can call Bozo->import. Since no import is defined in Bozo, the call is skipped.

But the second time you use Bozo, require doesn't load it because it was already loaded, and the import still doesn't exist, so nothing happens.

# script.pl package Burble; use Bozo; package Wibble; use Bozo; package main; print Burble::go_bozo(); # OK print Wibble::go_gozo(): # ERROR - doesn't exist

Now, add a package statement:

# Bozo.pm package Bozo; sub go_bozo { return "BOZO!\n" } 1;

Now, when you use Bozo the first time, go_bozo is compiled into the Bozo namespace rather that whatever namespace was in scope in the script file. (However, you still can't just call go_bozo because it hasn't been exported to the current package.)

# script.pl package Burble; use Bozo; package main; print Bozo::go_bozo(); # OK print Burble::go_bozo(); # ERROR - doesn't exist print go_bozo(); # ERROR - main::go_bozo() doesn't exist eithe +r

Once you've got that clear, it's time to understand Exporter. Exporter provides the import function that's been missing. Prior to Perl 5.8, you needed to subclass Exporter like this:

# Bozo.pm package Bozo; # subclass Exporter use Exporter; @ISA = ( 'Exporter' ); sub go_bozo { return "BOZO!\n" } 1;

That can be done shorthand with base:

# Bozo.pm package Bozo; # subclass Exporter use base 'Exporter'; sub go_bozo { return "BOZO!\n" } 1;

However, that still won't export go_bozo to the namespace that called use Bozo because you haven't told Exporter what you want to export.

# script.pl use Bozo; print Bozo::go_bozo(); # OK print go_bozo(); # ERROR - main::go_bozo() still doesn't exist

Exporter requires you to put the functions you want to export into a package variable called @Bozo::EXPORT. (So, yes, the lexical is the root of evil -- but that's because Exporter specifically calls for a package variable.)

# Bozo.pm package Bozo; # subclass Exporter use base 'Exporter'; # define exports @EXPORT = ( 'go_bozo' ); sub go_bozo { return "BOZO!\n" } 1;

Now, when you use Bozo the first time, Bozo.pm is compiled, putting go_bozo in the Bozo namespace. But now, Bozo->import() is called, and exports go_bozo to the caller's namespace. The second time use Bozo is seen, the compilation isn't repeated, but the call to Bozo->import() is, which exports go_bozo again to the caller's namespace. So now you can do this:

# script.pl package Burble; use Bozo; package Wibble; use Bozo; package main; use Bozo; print Bozo::go_bozo(); # OK print Burble::go_bozo(); # OK print Wibble::go_bozo(): # OK print go_bozo(); # OK

Does that make more sense now? Without the package you wind up compiling the function into the file that calls use Bozo but only the first time. That looks like an export, but it's really not. With the package statement you then have to get the Exporter part right.

-xdg

Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.


In reply to Re^3: "use Foo.pm" twice from inside different packages... by xdg
in thread "use Foo.pm" twice from inside different packages... by wazoox

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.