http://www.perlmonks.org?node_id=1046340

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

Hi All, I have defined some system specific variables in a .pm file and wanted to use those variables in all the perl scripts which use the .pm. This is how my Utilities.pm looks like
package Utilities; use Exporter; @EXPORT = ($SYS_DIR); our $SYS_DIR="/path/to/sys"; 1;
And here is the .pl file
use Utilities; use strict; print "This is the value for SYS_DIR=$SYS_DIR";

Replies are listed 'Best First'.
Re: Better way to define global variables
by choroba (Cardinal) on Jul 25, 2013 at 13:44 UTC
    You do not want to export the value of the variable, but the variable itself. Use
    @EXPORT = qw($SYS_DIR);

    Also, the Exporter's documantation states a different way how to make a package use it. Change the other line to

    use Exporter 'import';
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: Better way to define global variables
by Athanasius (Archbishop) on Jul 25, 2013 at 14:03 UTC

    Ok, you now know how to do this. Here’s why you shouldn’t! From Exporter#What-Not-to-Export:

    Do not export variable names. Just because Exporter lets you do that, it does not mean you should.

    @EXPORT_OK = qw( $svar @avar %hvar ); # DON'T!

    Exporting variables is not a good idea. They can change under the hood, provoking horrible effects at-a-distance, that are too hard to track and to fix. Trust me: they are not worth it.

    To provide the capability to set/get class-wide settings, it is best instead to provide accessors as subroutines or class methods instead.

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: Better way to define global variables
by kcott (Archbishop) on Jul 25, 2013 at 14:36 UTC

    G'day govindkailas,

    It's generally not a good idea to export by default (i.e. with @EXPORT) — see the Exporter documentation sections: Selecting What to Export and What Not to Export. Instead, consider using @EXPORT_OK and %EXPORT_TAGS.

    Here's an example of Utilities.pm that does that:

    package Utilities; use strict; use warnings; use Exporter qw{import}; my @sys_exports = qw{$SYS_DIR $SYS_OTHER}; my @util_exports = qw{$UTIL_THIS $UTIL_THAT}; our @EXPORT_OK = (@sys_exports, @util_exports); our %EXPORT_TAGS = (SYS => [@sys_exports], UTIL => [@util_exports]); our $SYS_DIR = "sys_dir"; our $SYS_OTHER = "sys_other"; our $UTIL_THIS = "util_this"; our $UTIL_THAT = "util_that"; 1;

    Here's some sample runs showing how to use it.

    No namespace pollution unless specifically requested:

    $ perl -Mstrict -Mwarnings -E ' use Utilities; say $SYS_DIR; ' Global symbol "$SYS_DIR" requires explicit package name at -e line 3. Execution of -e aborted due to compilation errors.

    Request a specific item:

    $ perl -Mstrict -Mwarnings -E ' use Utilities qw{$SYS_DIR}; say $SYS_DIR; ' sys_dir

    Request multiple items using a tag:

    $ perl -Mstrict -Mwarnings -E ' use Utilities qw{:SYS}; say $SYS_DIR; ' sys_dir

    Mix specific and tag requests:

    $ perl -Mstrict -Mwarnings -E ' use Utilities qw{:UTIL $SYS_OTHER}; say $SYS_OTHER; say $UTIL_THAT; ' sys_other util_that

    -- Ken

Re: Better way to define global variables
by davies (Prior) on Jul 25, 2013 at 14:28 UTC
Re: Better way to define global variables
by MidLifeXis (Monsignor) on Jul 25, 2013 at 13:51 UTC

    In addition to what choroba said, I am getting the same error as you are (although you didn't state it in your question, just in the CB): Global symbol "$SYS_DIR" requires explicit package name. Obviously I am missing something in the documentation. Adding strictures/warnings does not seem to help identify the problem.

    Update: The key was explicitly importing the import method with the use Exporter 'import' line. I missed it in my initial reading. Apply choroba's changes and you should be set.

    --MidLifeXis

Re: Better way to define global variables
by hdb (Monsignor) on Jul 25, 2013 at 14:02 UTC

    Any chance you have another Utilities.pm lying around? Try:

    use strict; use Utilities; print $INC{'Utilities.pm'},"\n"; print "This is the value for SYS_DIR=$SYS_DIR";

    and see whether you get the correct path.

    I have no problems with your code after making choroba's proposed changes.