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

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

Hi Monks, I am a Perl rookies that seek you wisdom. I am working on a project and I need to parse around some variables to separate modules I have created. Example:
use strict; use var qw($readMode $writeMode $appendMode); $readMode = ''; $writeMode = '>'; $appendmode = '>>'; sub openFile { my $mode = pop(@_) open(FILENAME, $mode, EXPR); }
I have multiply mudules that I will like to use the various file modes that I have define in this module say called "moduleA". In moduleB that is locate in a separate file, I use the following code;
use strict; require "moduleA.pl"; openFile("someOtherStuff", $readMode);
Whenever I run the code, I see the following error "Global symbol "$readMode" requires explicit package name at ..." Could any Monk kindly fill me with wisdom? note, I don't want to $readMode by way of a subroutine. Thanks

Replies are listed 'Best First'.
Re: Using Global Variables in Perl
by samtregar (Abbot) on Apr 22, 2008 at 16:57 UTC
    It's tempting to just tell you not to do that - global variables are generally a poor way to program. But as long as you promise to pick up a copy of Perl Best Practices you can do this in your modules:

    openFile("someOtherStuff", $main::readMode);

    This works because unless your modules declare a package all global variables are in the default "main" package.

    -sam

Re: Using Global Variables in Perl
by pc88mxer (Vicar) on Apr 22, 2008 at 17:12 UTC
    ++ on the Best Practices suggestion.

    I think this situation is a good candidate for using exported symbols. Have package moduleA export $readMode, etc. which other modules can import. The implementation would go something like:

    package moduleA; @ISA = qw(Exporter); @EXPORT_OK = qw($readMode $writeMode $appendMode openFile); $readMode = ''; $writeMode = '>'; ... 1;
    Then other modules can selectively import them into their own namespace via:
    use moduleA qw($appendMode openFile); ... # calls moduleA::openFile() with parameter $moduleA::appendMode: openFile(..., $appendMode); # note: no namespace qualifier needed
Re: Using Global Variables in Perl
by TGI (Parson) on Apr 22, 2008 at 17:50 UTC

    Global variables are generally to be avoided. If you must use them and have strict vars enabled, you must specify their package as well as their name: $main::foo.

    You should take a look at perlmod, perlmodstyle, and perlmodlib. They have some good information about how to write and use modules.

    A few things in your code sample jump out at me. I took the liberty of rewriting your code below. I haven't tested it, so there may be errors.

    # Save this file as 'MyModule.pm' package MyModule; # declare your module to be in a package, use strict; use warnings; # warnings can help catch logic errors, and typos use Carp; # issue warnings from calling code. my %HANDLE_MODES = ( # replace globals with package scoped lexical t +hat is NOT accessed outside the file. READMODE => '<', WRITEMODE => '>', APPENDMODE => '>>', ); sub openFile { my $file = shift; # shift automatically works with @_ my $mode = shift; # use strings to match keys in %HANDLE_MODES in +stead of global variables. # check to see if valid mode in call. if( exists $HANDLE_MODES{$mode} ) { # open a lexical filehandle, capturing any errors my $fh; my $error = open( $fh, $mode, $file) ? undef : $!; # return filehandle and error string. return ( $fh, $error ); } else { # if mode is bad issue error message pointing to calling code. croak "Illegal file handle mode '$mode'" } } 1;

    Calling code:

    use strict; use warnings; use MyModule; # load your module. # call openFile. my ($fh, $error) = MyModule::openFile('my/file/here.txt', 'READMODE' ) +; # Check results if ( $fh ) { # file opended ok, process file. # reading from a lexical handle works just like a global handle. while ( defined ( $foo = <$fh> ) ) { # do stuff } } else { # File did not open, show error. warn "Error opening file- $error\n"; }

    I hope this helps.

    Update: I forgot to make sure that the module example returned a true value. Fixed it. I told you I didn't test the code :)


    TGI says moo

Re: Using Global Variables in Perl
by mscharrer (Hermit) on Apr 22, 2008 at 17:18 UTC
    I would change the following:
    • use var qw(...) to the newer our $var, $var2,..;
    • Add a package moduleA; in your module file.
    • Either write $moduleA::readMode or use the Exporter package to export your mode variables to the main file
    BTW: Are you sure that pop(@_) is what I want, e.g. the last element of the list? Normally you do shift @_. In both cases the @_ is not needed because it's taken automatically inside a sub.
Re: Using Global Variables in Perl
by gzayzay (Sexton) on Apr 22, 2008 at 17:37 UTC
    Thanks Monks, I have gained wisdom and will learn to follow the best practice.

    You all a wonderfull.
Re: Using Global Variables in Perl
by FunkyMonk (Chancellor) on Apr 22, 2008 at 22:53 UTC
    I don't want to $readMode by way of a subroutine
    Why not?

    Global variables are evil. OO is the way to go.


    Unless I state otherwise, my code all runs with strict and warnings

      I guess by that logic I should convert all my little procedural syadmin perl scripts to OO? ;-)

      I'm more of a proponent of the "Right Tool for the Right Job"... :) It depends on what you're building.

        I honestly don't suggest or condone the use of global variables in this aspect... If you have the time to write out $varname you have the ability to just hard code >> << > < also like to point out your variable names are already identifyers it really needs to be just standard variables in this case however an option for global shared variables in the $_ENV in perl to control global variables over your filehandle multiplexing codes.