Perl 5.6 (?) introduced the new 'our' operator, which I have taken a liking to, as, once you understand the subtle differences between it and 'my' and 'local', it can improve readability and flexibility.

Is there anything wrong with declaring a typical package/module as follows:
package Xyz; use strict; use Exporter; our (@EXPORT) = qw [ FunctionAlpha FunctionBravo FunctionCharlie $calarDelta ]; our (@EXPORT_OK) = qw [ FunctionEcho $calarFoxtrot ]; our (@ISA) = qw [ Exporter ];
tilly's recent post, which was about the perils of BEGIN blocks, even though I recall that a while back they were 'the way to go' for export declarations, but this could have been an early Perl5 thing.

There are some curious things that some modules do to get things to run smoothly while under the influence of 'strict' and '-w', such as: All of these seem a little excessive for something that should be pretty simple.

Once I tried to write a wrapper filter that would auto-export any functions tagged 'exportable' but this was a war I could not win. Maybe in Perl 6.

Replies are listed 'Best First'.
Re (tilly) 1: Standard Package Preamble
by tilly (Archbishop) on Apr 17, 2001 at 01:32 UTC
    It is almost expected of me, that I would have to point to Why is 'our' good? for an explanation of what I don't like about our, and Trivial style ideas giving my alternate answer to the above issue. In the above example my standard would look like this:
    package Xyz; use Exporter; @ISA = 'Exporter'; @EXPORT_OK = qw [ FunctionAlpha FunctionBravo FunctionCharlie FunctionEcho $calarDelta $calarFoxtrot ]; use strict; # etc
    Note that I dropped @EXPORT. Read the documentation for Exporter for an explanation of why.

    Sometimes I will move strict up and use vars to declare the globals. Usually not.

Re: Standard Package Preamble
by dws (Chancellor) on Apr 17, 2001 at 02:08 UTC
    If your intent is to have a standard preamble, then adding $VERSION and assigning it a value might be a good touch. Extra credit if you can set it straight from CVS.

    Do your typical packages export symbols? Mine don't, so (for my purposes) I forgo the use Exporter incantations.

      "Do typical packages export symbols?"

      I find that as long as I tend to export a lot of symbols from packages that are function based, but usually none from object-oriented modules. In the case of the function based packages, I'm usually importing a bunch of common routines that are used fairly frequently on a project, and the intention is to save having to prefix each call with the package name.

      Of course, at that point it can become unclear where certain functions came from, which is not unlike C header files, so I try to keep the names of the functions distinct and explanational in order to avoid collisions and confusion.

      I am curious about your suggestion of CVS integration, though. Any hints on how you might get a numeric only "release" number out of it, as the numeric version does not always increment linearly when you use branching. Generally I don't use $VERSION since the module usually upgrades with the rest of the code in parallel.
(tye)Re: Standard Package Preamble
by tye (Sage) on Apr 17, 2001 at 22:02 UTC

    First, I'll note that I don't like our for the simple reason that it makes your package no longer work for older but fairly recent versions of Perl. If there were some significant advantage to its use, then I might start using it anyway. As it stands, I agree with tilly's analysis that our actually offers more disadvantages than advantages.

    Moving use strict after your declarations doesn't make any sense to me. The point of use strict it to quickly catch typos in an obvious way so you can immediately fix them rather than spending a lot of time trying to figure out why things aren't working. Well you can still make typos in your standard variable declarations, so why not protect yourself from those?

    If you have warnings enabled, then certain typos will be caught for you but a great many others won't. For example, typing $VERSON= 1.01; would generate a warning about a variable being used only once but @VERSION= 1.01; would generate no warning. Writing @EXPORT_OKAY when you meant @EXPORT_OK or @EXPORT_TAG when you mean %EXPORT_TAGS also won't be caught (variables named "VERSION" or /^EXPORT.*/ are exempt from the "used only once" warning).

    Even worse, you won't be allowed to use any of the standard variables later in your code. If you decide to include the module version number in an error message or some persistant data or return it to the user, you'll get a fatal error for mentioning $VERSION.

    Even if you don't currently use $VERSION in your code, why set yourself up for a maintenance problem down the road? (Or worse, a maintenance problem for the person that inherits your code.)

    Is there some advantage to not using strict on your standard variables? I guess it saves you one use vars line (if that, since you will often have to use vars for some "non-standard" package variables anyway). That isn't much savings at all. And I like the use vars line because it means that I'd have to make the same typo at least twice for it to not be caught.

    Another place for un-caught typos is @ISA. That is why I'd use base qw( Exporter );. If you mispel "Exporter" in that line, you'll get a fatal error (unless you manage to correctly spell the name of a different installed module).

    Finally, the BEGIN block issue. Whether you use vars or our (or even my), you are declaring your variables at compile time but initializing them at run time. This leaves a window where you can end up using the variables before they are initialized.

    I've been bitten by this and have seen several people get bitten by this in a variety of situations (some even here at the Monastery). Some of these incidents lead to the change to perlmod.pod that suggests using a BEGIN block to initialize your package variables. Although most of the incidents I've been able to dig up recently have involved someone doing something that you could argue they shouldn't be doing, I find that the BEGIN block allows, at least, "robustness in the face of stupidity", so I use it. Without the BEGIN block, you get a hard-to-diagnose failure that will probably suck up a lot of your time trying to figure out how to fix it.

    Anyway, these cases have been plenty to convince me of the value of initializing global and file-scope variables inside of BEGIN blocks and have been enough to get someone else to change perlmod.pod and get those changes accepted. The BEGIN block only adds a slight bit of extra complexity.

    So my standard package preamble is something like:

    package Xyz; use strict; use warnings; # highly optional but be sure to test with warnings on use base qw( Exporter ); use vars qw( $VERSION @EXPORT_OK ); BEGIN { @EXPORT_OK= qw [ FunctionAlpha FunctionBravo FunctionCharlie $calarDelta FunctionEcho $calarFoxtrot ]; }

            - tye (but my friends call me "Tye")
      'use base' is a nice trick, something that certainly goes a step in the right direction instead of making @ISA references, which are a little strange anyway. At first sight, I was expecting something like @PCI to show up there for whatever equally mysterious reason.

      Am I crazy to dream of a SuperExporter which could handle all of this for you automatically?
      package Xyz; use strict; use SuperExporter ( EXPORT => qw [ FunctionAlpha FunctionBeta FunctionCharlie $scalarDelta ], EXPORT_OK => qw [ FunctionEcho $scalarFoxtrot ], VERSION => '1.0.2.3', );
      Which would eliminate the unsavoury 'use vars', BEGIN{}, and a host of other strangeness, all at the expense of a non-standard module with a customized 'import()' routine. A bargain at half the price!

        Such would be easy to write. I suspect things don't work that way now for fear of a performance hit...

        Which gave me a bit of a neat idea. If you adjust the usage slightly to use anonymous array references (which is pretty much required anyway):

        use Exporter::Easy ( VERSION => \'1.01', EXPORT => [qw[ FunctionAlpha FunctionBravo $calarCharlie ]], # etc. ); # (Closing delimiters look so sad when alone like that.)
        then you can just "export" the @EXPORT array into place without even having to copy the list of symbols:
        sub import { my $pkg= caller; push @{$pkg."::ISA"}, "Exporter"; while( @_ ) { my $key= shift; # (insert validation code here) *{$pkg."::".$key}= shift; } }
        which also takes care of the use vars functionality.

        Seems like a worthy module to me!

                - tye (but my friends call me "Tye")