Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

standard perl module and BEGIN block.

by hartzell (Sexton)
on Aug 16, 2004 at 18:27 UTC ( [id://383399]=perlquestion: print w/replies, xml ) Need Help??

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

I've been setting up a standard module.pm template for several folks to use. The perlmod man page suggests this:
BEGIN { use Exporter (); our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS); # set the version for version checking $VERSION = 1.00; # if using RCS/CVS, this may be preferred $VERSION = sprintf "%d.%03d", q$Revision: 1.1 $ =~ /(\d+)/g; @ISA = qw(Exporter); @EXPORT = qw(&func1 &func2 &func4); %EXPORT_TAGS = ( ); # eg: TAG => [ qw!name1 name2! ], # your exported package globals go here, # as well as any optionally exported functions @EXPORT_OK = qw($Var1 %Hashit &func3); }
But that ExtUtils-ModuleMaker-0.32 (which I found via a module best-practices thread) does this:
BEGIN { use Exporter (); use vars qw ($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); $VERSION = 0.01; @ISA = qw (Exporter); #Give a hoot don't pollute, do not export more than needed by +default @EXPORT = qw (); @EXPORT_OK = qw (); %EXPORT_TAGS = (); }
and other examples (that I can't find at the moment) do without the BEGIN block. I'd like to be able to explain the differences to other folks, but don't know all of the history, so I have a few questions:
  1. I think that "use vars" is obsolete and that "our" is prefered. But I think that using "our" impacts backward compatibility? Or is there more going on?
  2. I think that modules should put their module setup stuff (VERSION, ISA, EXPORT*) in a BEGIN block so that it's available at compile time (since that what the BEGIN block does...), but I'm not clear on who takes advantage of it.
  3. In order to leverage the justification in 2., should I put all of the module's that the package in question "uses" into the begin block, or just the module def'n stuff?
g.

Edit by tye, replace PRE with CODE

Replies are listed 'Best First'.
Re: standard perl module and BEGIN block.
by tilly (Archbishop) on Aug 16, 2004 at 19:09 UTC
    The perlmod man page is showing every piece that you might want to include. Most of them you do not need to include in any given module. Furthermore as a best practice I strongly suggest not including @EXPORT or %EXPORT_TAGS.

    The BEGIN block looks useless to me. Its only important effect in the first version is to limit the scope of the variables declared with our. In the second version it does nothing useful.

    On our vs use vars, I do not consider vars obsolete. What it does it does better than our does. See Why is 'our' good? for more detail on why I think that.

    The parens after Exporter is a subtle micro-optimization, they avoid calling Exporter::import when it will be doing nothing. You can do it if you want - it certainly doesn't hurt - but I usually don't worry about things like that unless performance is a known problem.

    I'd suggest a template that looks something like this:

    package Foo; use Exporter; @ISA = qw(Exporter); @EXPORT_OK = qw(); # Exportable things go here $VERSION = 0.01; use strict; # Functions etc go here. 1; __END__ =head1 NAME Foo.pm - What is it? =head1 SYNOPSIS use Foo; # Do something with it. =head1 DESCRIPTION Yada, yada. =head1 EXAMPLES =head1 AUTHOR
    Note the trick of putting the special variables before strict.pm, eliminating any need to bother declaring them.
      Note the trick of putting the special variables before strict.pm, eliminating any need to bother declaring them.

      Doesn't that "trick" make sections of the code position dependant? Doesn't that at least warrent a comment explaining that?

      I think that either our or use vars is preferable.


      Examine what is said, not who speaks.
      "Efficiency is intelligent laziness." -David Dunham
      "Think for yourself!" - Abigail
      "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
        And here I was under the impression that my pointing out the trick was a comment.. :-D

        Seriously now, you're right that it does make that section of the code depend on position. Which I don't see as a horrible thing - no worse than a lexically scoped variable. And certainly not in boilerplate initialization code which many people who use it won't expect to understand.

        If you're uncomfortable with that fact you can always declare the variables as is usually done. In fact I pointed out that I'd done it so that people could make that choice.

        Also I deliberately didn't comment on the mechanics. If I thought that the mechanics required commenting on within the code, then I'd first try to solve that by changing the mechanics, not commenting the code.

Re: standard perl module and BEGIN block.
by ikegami (Patriarch) on Aug 16, 2004 at 18:36 UTC

    Re item 2: Check out the node inheritance problems for an example of where BEGIN { @ISA = ... } was useful.

    Re item 3: BEGIN { use ... } is redundant.
    use Module; is about equiv to BEGIN { require Module; Module->import(); }
    use Module (); is about equiv to BEGIN { require Module; }
    use Module qw(list); is about equiv to BEGIN { require Module; Module->import(qw(list)); }

Re: standard perl module and BEGIN block. (less)
by tye (Sage) on Aug 16, 2004 at 20:28 UTC

    I'd leave most of the things out of the BEGIN blocks because most of them will already happen at compile time.

    I'd do this for an OO module

    package My::Package; use strict; use vars qw( $VERSION ); $VERSION = 0.01; # If you inherit from some other module (use sparingly): #use base qw( ... );

    or, if you use inheritance (I've become more suspicious of base.pm even though I hardly ever use it since I hardly ever use inheritance in Perl):

    package My::Package; use strict; use vars qw( $VERSION @ISA ); BEGIN { $VERSION = 0.01; @ISA = qw( ... ); }

    where the BEGIN block shouldn't be needed for "normal" module situations but can be useful in unusual situations (that are often better to just avoid).

    For a non-OO module:

    package My::Module; use strict; use vars qw( $VERSION @EXPORT_OK %EXPORT_TAGS ); BEGIN { $VERSION = 0.01; @EXPORT_OK = qw( ... ); %EXPORT_TAGS = ( ... ); require Exporter; *import = \&Exporter::import; }

    where (again) the BEGIN is usually not needed. Remove %EXPORT_TAGS if you don't use it (it is useful if your module supports exporting groups of symbolic constants).

    Inheriting from Exporter to just get an import() is a bad idea. It means you get *all* methods that Exporter defines even the ones you didn't even know about. This over-use of inheritance has lead to lots of modules using "autoloading" w/o having been designed to use autoloading which means that a simple mispelling of a method name gives a cryptic error about not finding some "*.al" file (which makes you think you've installed the module incorrectly rather than that you've mispelled a method name).

    I don't use our, it makes code less backward compatible, it is confusingly complex (though often doesn't appear that way on the surface), and it is easy to abuse.

    You can also add "use warnings;" after "use strict;", though there are also good reason to not do that. I'm a big fan of warnings being on during development but leaving them on in production is a net loss in my book unless you do the hard work of setting up the back channel so that the information from the warnings gets back to the developers and does't annoy the users. (And warnings.pm isn't included in versions of Perl that have now become rather old.)

    - tye        

Re: standard perl module and BEGIN block.
by petdance (Parson) on Aug 16, 2004 at 22:12 UTC
    Before you go too far down the road of a standard module template, please take a look at Module::Starter. It addresses many of the concerns of module templating, and it's extensible.

    xoxo,
    Andy

      Shameless self-plug: Given that there are many different individual styles for writing module distributions, please consider ExtUtils::ModuleMaker::TT, which extends ModuleMaker to allow user-defined templates for all the skeleton files of a distribution using the Template Toolkit and a pre-defined configuration file with default settings for ModuleMaker. I wrote it to work out some frustrations with the cumbersome process of creating module distributions with the standard tools and then having to edit all the boilerplate. As always, any feedback would appreciated.

      -xdg

      Code posted by xdg on PerlMonks is public domain. It has no warranties, express or implied. Posted code may not have been tested. Use at your own risk.

        FYI, Module::Starter will handle the TT.

        xoxo,
        Andy

Re: standard perl module and BEGIN block.
by hardburn (Abbot) on Aug 16, 2004 at 19:04 UTC

    Are you writing plain reusable modules, or object-based modules. In object-based modules, you rarely need or want to use Exporter. You'll still want/need $VERSION and @ISA, but the rest of the variables can go.

    If you're not using object-based modules, you still don't necessarily need Exporter, but it can be nice. If you still use it, it wouldn't hurt to delete @EXPORT entirely.

    "There is no shame in being self-taught, only in not trying to learn in the first place." -- Atrus, Myst: The Book of D'ni.

Re: standard perl module and BEGIN block.
by dragonchild (Archbishop) on Aug 16, 2004 at 18:29 UTC
    I don't think I have used a BEGIN block more than 2-3 times in my career. *shrugs* YMMV.

    As for who can take advantage of it ... well, other BEGIN blocks, CHECK blocks, INIT blocks ... again - I've never written a CHECK or INIT block in my career, and don't think I ever will. (Not in Perl5, at any rate.)

    I don't know the history behind this construct, but I'm thinking it's very cargo-cultish.

    ------
    We are the carpenters and bricklayers of the Information Age.

    Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose

    I shouldn't have to say this, but any code, unless otherwise stated, is untested

      BEGIN is the sort of thing you write when you have code-generation tasks or want to otherwise have done work appropriate to a compile-time categorization. I wouldn't ordinarilly include things like setting $VERSION in that though there is some sense in including Exporter specific information at compile-time (even though it isn't code generation) - other things that have to run at compile-time are allowed to care about that information so it is potentially relavent at that time.
Re: standard perl module and BEGIN block.
by coreolyn (Parson) on Aug 16, 2004 at 18:41 UTC

    I've had to use it to take care of cross-platform issues. Utilizing it to set up enviornmental vars and module libraries based on what OS the script is running in.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://383399]
Approved by coreolyn
Front-paged by mattriff
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (9)
As of 2024-04-18 08:50 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found