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

I'm looking for more specific answers on packages and scoping of variables. I have gone though many resources and can not seem to get the full understanding of it all. specifically,

If i have on script that requires a package of subroutines and a few variables.
All package variables are Global, correct?
I need to use strict; Do I declare my package variables with my?
Can i do this in my subroutines in the package?
When running under use strict;does the main script need to use $main::var or &main::sub for things directly in the script.

I am somewhat overwhelmed by this concept at the moment. Hopefully this will bring some understanding to my delema. I think that is all the issues i have to worry about, but if anyone thinks of more, by all means let me know.

Replies are listed 'Best First'.
Re: About packages and scopes
by cLive ;-) (Prior) on Nov 19, 2001 at 22:08 UTC
    Under strict, global variables must contain the package name, eg:
    # CGI post max $CGI::POST_MAX = 4096; # if you are using strict, the global # variable age in your 'main' script # would need to be like this $main::age = 31; # or (same) with implicit namespace of 'main' $::age = 31;
    If the package correctly exports variables/subs, they will be available in the namespace you are in. In the case of the CGI module, you can choose which elements are exported, eg
    use CGI qw/:standard/; print header(), start_html(), h3('hello'), end_html();
    Take a look at the module for examples of other possible values.

    Using 'my' to declare variables is best practice where possible. If you really do need truely global vars, then define by prepending "namespace::".

    If you are not using strict, just defining a variable implies that the variable is global, ie:

    # no strict, so.. $age = 31 # is the same as these (in the 'main' script): $::age = 31 $main::age = 31

    If you look, you will see that CGI.pm is NOT using 'strict', so it can define global variables such as $POST_MAX that are global, without having to explicitly using the package name.

    But because these are global, you can access them from other packages through the namespace, eg:

    $CGI::NPH=1

    Still not very clear, is it? :) Why not create some play packages to experiment until this all sinks in?

    Just my morning .02

    cLive ;-)

    Update: - please read tilly's comments below as well for info on stuff I didn't know about (our & vars - I still use Camel V2...). Also, added 'of main' to 'implicit namespace in code to avoid (possible) confusion. (All I meant was that $main:: and $:: are equivalent, with the main being implied in the $:: case. Not as Tilly thought, that $:: implies the current package.

      Some mistakes and corrections.

      First of all with strict on you can declare global variables with vars or (in 5.6) with our. (I prefer vars.) Then you don't have to use fully qualified names. In fact doing this is both customary and preferred, because it extends strict's typo checking to global variables, and makes it easier to change what package code is written for. (I would, in fact, assume that anyone routinely using fully qualified names instead of declaring them is simply unaware of how to declare them. Furthermore I would strongly suggest rewriting code which uses lots of fully qualified names without very specific cause.)

      Secondly and more importantly, your comment about "implicit namespace" on the $::foo construct is likely to mislead, and may indicate confusion on your part. Writing $::foo does not declare a global in your current package. Instead it declares a global in package main.

      How does this work? Well it is simple. Your root namespace is main. In main there is a package main:: which is a reference to the root namespace again. Therefore $::foo is the same as $main::foo is the same as $main::main::foo, etc. (Likewise $foo::bar is the same as $main::foo::bar.) So $::foo is a fully qualified name of a global variable in package main, not your current package.

      Therefore there is nothing really implicit about $::foo. And nobody should let the word "implicit" fool you into thinking that it is in the current package. It is in package main.

      UPDATE
      Added a closing bracket. danger caught the typo.

      Short and sweet. Thanks, it did help. I will try a few things and see what happens
Re: About packages and scopes
by dragonchild (Archbishop) on Nov 20, 2001 at 00:17 UTC
    To further clear (muddy??) the waters, it seems that you're asking about scoping as it relates specifically to packages. A package is nothing more or less than a new namespace. A namespace is nothing more than a hash, called a symbol table, that contains, as its members, references to all the non-lexical variables within the namespace. In fact, the definition of being within in a namespace is to be contained within that specific hash. (For the curious, the hash for a namespace 'Foo::Bar' is %Foo::Bar::, so you can iterate over it, etc.)

    A lexical variable is a variable that is accessible only within its inner-most enclosing scope. It's declared using my and cannot be accessed outside that scope. Period. Now, a variable declared with my at a file level is considered to be withing the implicit scope of the package. Still unaccessible outside that scope. (Closures are an indirect access to a lexical variable, so aren't really part of this discussion.)

    Variables that are either not declared at all or declared with our or local are inserted into the symbol table of that namespace. If declared, they're considered to be block-scoped globals. The primary difference, simply put, between our and local is that our is 5.6+, but works under strict vars. local does not. (There's more to it than that, but look around the Monastery and you'll find more on it than you'll ever want to know.)

    What does all this have to do with packages? Well, if you want to access a variable declared in package Foo from package Bar, you have to make sure you either are not using strict vars (Bad idea!!!) or have declared your variables with our. At this point, you can do a number of things.

    1. Use Exporter. Read up on the documentation how this would work.
    2. Use the fully-qualified name. $Foo::MyVar or something like that.
    3. Make Foo a class and create a method to access it.
    I hope this helps.

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

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

Re: About packages and scopes
by alien_life_form (Pilgrim) on Nov 19, 2001 at 23:26 UTC
    Greetings,

    Looks to me that some order is needed in the way we are slinging around definitions, lest confusion overcomes us.
    Let us (sensibly) define global a variable that can be accessed by any point of your program. By this token, then, package variables have global scope: the shorthand that allows one to omit the package name is actually irrelevant to the visibility issue.

    On the other hand lexical (my) variables can never achieve global status, as they are never inserted into any symbol table: their visibility is determined by the outermost enclosing block (or, file). This is the reason why 'strict vars' will not affect lexical variables.

    On a third hand :), lexical variables are refernce counted, (whereas package variables are not: how copuld they?) and can therefore assume a sort of global visibility if properly wrapped in code (closures).


    Cheers,
    alf


    You can't have everything: where would you put it?
Re: About packages and scopes
by staeryatz (Monk) on Nov 19, 2001 at 22:25 UTC
    You asked if all package variables are global. According to my Perl 5 book, that statement is false.

    From what I've read about Perl packages (I'm still also learning it, myself), is that "global" package variables are global to the package, and not neccessarily global to the program.

    $PackageName::variablename would be the syntax to access these "global" variables.
      It is possible that i assumed it meant the program when it was the package. But wouldn't that make it lexical? I need a beginners guide to perl packages. This was from the O'reilly Programming Perl. Upon futher inspection, there are no global variables in perl, just package variables.
        There are a handful of global variables -- punctuation ones, mostly.

        _____________________________________________________
        Jeff[japhy]Pinyan: Perl, regex, and perl hacker.
        s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

        Wouldn't that make it lexical? Good question.

        The answer is no, because lexical variables expire once they are outside a certain scope, and cannot be referenced outside of that scope.

        Global package variables on the other hand, can be accessed at any time, as long as you use the package names and colons preceeding the variable name.

        Hope that clears up a few things...