SPUG: Modules - more than one object in file?

Brian Ingerson briani at activestate.com
Wed Oct 11 13:21:45 CDT 2000


Todd Wells wrote:
> 
> I'm creating a module which uses some other objects internally, so I have
> multiple package statements in the same .pm file to define these other
> objects.  Is there a good reason why I shouldn't do this?  I'd prefer to
> keep it all in one file.  However, I'm having a problem which I think is
> related.

There seems to be a lot of fuzziness among the common Perl community, as
to what *order* Perl executes all of the source code that you give it.
Perlers talk about 'compile time' and 'run time', but in reality the two
are very much mixed together. For example you can use BEGIN blocks to
'run' code during 'compile' time, and eval blocks to 'compile' Perl
during 'run' time. 

There are a few things I have found along my journey, that help clear
the waters a bit.

1) use Foo qw(Bar Baz);
     is equivalent to:
   BEGIN {
       require Foo;
       Foo->import(qw(Bar Baz));
   }

   so you could infer, that 'BEGIN' is the only real compile time
directive.

2) require Foo;
     is similar to:
   eval `cat Foo.pm`;

   eval, as you know, compiles and runs a piece of Perl code.

3) In corollary, the statement:
  
   use Foo qw(Bar Baz);

   will:
     A) immediately read in Foo.pm.
     B) compile the code, executing each BEGIN (and use) as it goes.
     C) run the (file scoped, or global, or non-subroutine) code of
Foo.pm
     D) call Foo->import(qw(Bar Baz));
     E) continue compiling the next line after 'use Foo ...'

A couple weeks ago I wrote some sample code to verify this process. The
code is in 4 files, shown below:

-------------------8<----------------------
# foo.pl
use X;
sub END {print "foo END\n"}
print "foo global\n";
sub INIT {print "foo INIT\n";}
sub CHECK {print "foo CHECK\n";}
sub BEGIN {print "foo BEGIN\n";}
use Z;
-------------------8<----------------------
# X.pm
package X;
sub END {print "X END\n"}
sub unimport {print "X unimport\n"}
print "X global\n";
sub import {print "X import\n"}
sub INIT {print "X INIT\n"}
sub CHECK {print "X CHECK\n"}
sub BEGIN {print "X BEGIN\n"}
use Y;
1;
-------------------8<----------------------
# Y.pm
package Y;
sub END {print "Y END\n"}
print "Y global\n";
sub import {print "Y import\n"}
sub INIT {print "Y INIT\n"}
sub CHECK {print "Y CHECK\n"}
sub BEGIN {print "Y BEGIN\n"}
1;
-------------------8<----------------------
# Z.pm
package z;
sub END {print "z END\n"}
print "z global\n";
sub import {print "z import\n"}
sub INIT {print "z INIT\n"}
sub CHECK {print "z CHECK\n"}
sub BEGIN {print "z BEGIN\n"}
1;
-------------------8<----------------------

If you run 'perl foo.pl' you get:
X BEGIN
Y BEGIN
Y global
Y import
X global
X import
foo BEGIN
z BEGIN
z global
z CHECK
foo CHECK
Y CHECK
X CHECK
X INIT
Y INIT
foo INIT
z INIT
foo global
z END
foo END
Y END
X END

Note: You'll need 5.6 for CHECK to work.

Try perl -c foo.pl to see where Perl thinks compile time ends. 
Notice the difference in execution order between INIT and CHECK.

As I took the time to understand this, my confidence in knowing what
Perl was doing with my code really solidified.

Hope this helps.

Brian

 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     POST TO: spug-list at pm.org       PROBLEMS: owner-spug-list at pm.org
      Subscriptions; Email to majordomo at pm.org:  ACTION  LIST  EMAIL
  Replace ACTION by subscribe or unsubscribe, EMAIL by your Email-address
 For daily traffic, use spug-list for LIST ;  for weekly, spug-list-digest
  Seattle Perl Users Group (SPUG) Home Page: http://www.halcyon.com/spug/





More information about the spug-list mailing list