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

Global variables generally make me uneasy. Given this, I've always used strict; and declared everything with my (guess that's a given with use strict;)

What I didn't quite understand is that my variables that are declared in the main body of a program are accessable anywhere within that file/package. I realized this after I accidentially did what I thought you could not do; use a variable within a sub that was defined in the body of the script and not passed to the sub.

Now my question is more on the subject of best practices with Perl. Is it considered a faux pas to refrence these varialbes globally? Or is it considered redundant to pass them subs?

Or is there some other practice that I'm unaware of?

Thanks in advance
Rich

Replies are listed 'Best First'.
(Ovid) Re: Top level
by Ovid (Cardinal) on May 23, 2001 at 22:14 UTC

    It is not a faux pas to access my variables globally, it's impossible (well, kind of). Global variables are attached to a namespace and that is how other packages access them. my variables are limited to the scope they are declared in.

    Often, I'll establish my database connection that the beginning of a package and allow all subs in that package to use the lexically scoped DBI object. This works well if I have many places that use it.

    Global variables tend to be more dangerous if they are shared between packages. This makes the packages interdependant. If you need to change a global in one package, you need to search through all other packages that reference this global variable and update them. This is a Bad Thing.

    Of course, this also occurs when you have a my $var at the top of a particular package. If you have a bunch of subs that use it and you need to change the name, this could be problematic, but generally much less of an issue than if you're using a global across different packages.

    Terminology alert: my variables declared in a package can only be accessed in that package. They are not globals and can only be accessed in the scope in which they were declared. Try the following (strict deliberately not used):

    use Data::Dumper; $x = 1; print Dumper( \%:: );

    By examining the output, you'll see that $x is in the main namespace. However, by putting a my in front of $x, it's removed from the namespace.

    One thing I am unclear on, though: what mechanism does Perl use to access those variables that are lexically scoped and not in a namespace?

    Cheers,
    Ovid

    Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

      A file is a 'block', hence, unbracketed my's have file scope.
      (That is, if there is more than one package in a file, the variable can be seen from all packages;
        if one package is in more than one file, only code in that one file can see the variable.)

      p

Re (tilly) 1: Top level
by tilly (Archbishop) on May 23, 2001 at 22:20 UTC
    I don't consider the label important. A non-global used as a global has the issues of a global. See Pass by reference vs globals for more on this. In particular it expresses some of my thoughts on what is bad (and not always so bad) about globals.

    As I am fond of saying, knowing what the rule officially is is not as important as knowing why that rule evolved and what the tradeoff is. There is always a tradeoff.

    BTW Code Complete has an excellent discussion on global variables.

Re: Top level
by sierrathedog04 (Hermit) on May 23, 2001 at 22:22 UTC
    Chapter 4 of the third edition of Programming Perl ("the Camel book") states:
    lexical variables are totally hidden from the world outside their immediately enclosing scope.
    Because your subroutine is defined inside the scope where you defined your lexical (my) variable the behavior you observe is normal and expected.

    If, admirably, you wish to encapsulate your main program's lexical (my) variables from your subroutines, one way to do it is simply to enclose your main program in braces. That removes your subroutine from the scope that contains your lexical variables.

    Thus the following program fails with the error "Global symbol '$myString' requires explicit package name.":

    use strict; {my $myString = "hello"; mySub();} sub mySub{ print $myString; }
Re: Top level
by tune (Curate) on May 23, 2001 at 22:09 UTC
    I used to leave only counters, and constants in global variables, or in any other special case. Otherwise I pass variables to subroutines, and I just create variables in the scope it is used. So there are no variable name confusions, etc. Of course these methods are used with strict, so it notifies me if am wrong.

    --
    tune

Re: Top level my vars and their global use in a file
by stephen (Priest) on May 23, 2001 at 23:51 UTC

    Strictly speaking, file-scoped lexicals (my variables declared outside of a block) aren't globals. They can be dangerous all the same. They'll work fine. However, in longer programs, they can make things difficult to debug. If I have a couple of subroutines

    use strict; my $id = 24601; sub foo { # .. lotsa code print "ID number is", $id, "\n"; # .. more code } sub bar { if ($id = 3) { # Oops-- I've accidentally set $id to 3 # do something subtle } }
    If ID isn't supposed to be 3, I'll stare at the code for foo() for hours trying to figure out what's wrong with it, since that's where the odd value got printed out. Plus, the malfunction will only occur if I first call bar(), then foo(). Once something done in one subroutine can invisibly affect the outcome of another, then the predictability of what my program does has just dropped tremendously. When my program does something I can't predict, that's generally a bug.

    If I pass $id as an argument, though, I'm stating explicitly that the actions and results of foo() are dependent on the value of $id. Also, common idiom will keep me from changing the value of my arguments unless I explicitly document otherwise.

    If I use $id absolutely everywhere, and it's getting really irritating passing it around all over the place, at least put it behind some get-set routines. That will limit its scope and enable you to control how it is set, and make access stand out in the program. For example:

    BEGIN { my $id = 24601; sub get_id { return $id; } sub set_id { my ($new_val) = @_; $id = $new_val; } } sub foo { # .. lotsa code print "ID number is ", get_id(), "\n"; # .. still more code }

    Some will say that file-scoped lexicals are less of a problem on smaller programs. I mostly agree, except that small programs have an astonishing ability to become large programs, and their code quality rarely improves on the way.

    I find package variables less dangerous than file-scoped lexicals, simply because one is disposed to declare them at the top of the program with use vars(). Better yet, if the "variable" isn't supposed to vary, use use constant instead. If you do use them, document that use in each subroutine that uses it, and declare each file-scoped lexical at the top of the file with a comment saying what it is.

    So, in summary, I'd avoid worrying about the "politeness" of it. :) Instead, I'd avoid using file-scoped lexicals because it makes your life easier.

    stephen

    Note: Code in this node is not tested, since it's primarily conceptual.
Re: Top level my vars and their global use in a file
by DrZaius (Monk) on May 23, 2001 at 23:39 UTC
    If you are using perl 5.6, you can use our to declare a variable as global. It is the equivilant of calling use vars qw().

    This is more sugar than functionality, I believe. Using this will make your code more readable.

    cheers.

Re: Top level
by DrSax (Sexton) on May 23, 2001 at 22:29 UTC
    It is hard to say on this one. I personally have used both practices, though I tend to avoid referring to something outside of a sub-routine that was not passed in. Let's say that I'm going to write a very short script that's about a page of text; I will refer to a my global from a sub in that case. Anything over a page long needs rigor. If someone else might have to modify it, all bets are off: no global refs.
    DrSax