Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Scope, package, and 'my' variables

by ff (Hermit)
on Jan 04, 2005 at 17:56 UTC ( #419327=perlquestion: print w/ replies, xml ) Need Help??
ff has asked for the wisdom of the Perl Monks concerning the following question:

There are occasions when it is convenient to group my work into packages that are all coded within the same perl program. I'm finding Perl's treatment of variables that I declare with 'my' a little nonintuitive, though. I'm getting warnings about a variable masking earlier declaration in same scope, and if that's the case, I'm wondering why the variable doesn't then use the originally "set" value?

3rd Ed. Perl Camel book, p. 290 says that:

Variables declared with 'my' are independent of packages; they are always visible within, and only within, their enclosing scope, regardless of any package declarations.
What I originally assumed was that the package statements would provide enough scope to allow me to reuse variable names within the respective package sections. And this works fine if the packages are stored in separate files and I use 'require' to access them.

But the perl code below is producing the following error messages:

"my" variable $var masks earlier declaration in same scope at E:\aa\pa +cktest.pl line 16. "my" variable $var masks earlier declaration in same scope at E:\aa\pa +cktest.pl line 29. Use of uninitialized value in concatenation (.) or string at E:\aa\pac +ktest.pl line 32. Use of uninitialized value in concatenation (.) or string at E:\aa\pac +ktest.pl line 43. Use of uninitialized value in concatenation (.) or string at E:\aa\pac +ktest.pl line 22.
To me it would seem that if I'm getting a message about a new 'my' declaration of a variable, that the new declaration would be ignored and the previous value would still be in effect, since, according to the quote above, it would seem that the 'my' variables are all being declared within the "top level" scope of the one file (the program). But then the error messages and the output (as noted below the program) show that no info is reaching the later invocations of the variable. So it seems that these later invocations neither have nor eat any cake....

When I attempt to give the packages their own scope (uncomment those {} lines in the packages to make their contents their own block), the complaints about "my" masks earlier declaration go away, but only the 'aaa' block accesses the contents of the variable. (i.e. output is the same and the other error messages still appear.)

So, is there a convenient way to insure that if I reuse names of variables across my various packages packed within a single file that I won't have collisions, or must I watch out to never reuse a variable name if I join all my packages into a single file as demonstrated here? (Secondarily, I have an uneasy feeling that my setting of variable values at the start of my packages isn't going to work, i.e. be available for the various subs, the way I want it to.)

Thanks

package aaa; #{ use strict; use warnings 'all'; my $var = 'first var'; sub do_a { print "In 'aaa' var is set to '$var'\n"; } #} package main; use strict; use warnings 'all'; my $var; aaa::do_a(); bbb::do_b(); ccc::do_c(); print "In 'main' var is set to '$var'\n"; package bbb; #{ use strict; use warnings 'all'; my $var = 'second time for var'; sub do_b { print "In 'bbb' var is set to '$var'\n"; } #} package ccc; #{ use strict; use warnings 'all'; sub do_c { print "In 'ccc' var is set to '$var'\n"; } #}
The above code produces the following output:

In 'aaa' var is set to 'first var' In 'bbb' var is set to '' In 'ccc' var is set to '' In 'main' var is set to ''

Updated Steve_p - added readmore tags

Comment on Scope, package, and 'my' variables
Select or Download Code
Re: Scope, package, and 'my' variables
by friedo (Prior) on Jan 04, 2005 at 18:10 UTC
    my variables are lexicals, and are scoped to the enclosing block. You can change the package name all you like; all that matters to a lexical variable is where the block ends. In your example, you declare my $var and set it to 'first var'. You then, after switching to package main, declare my $var again, setting it to nothing. Since lexicals don't care about packages, and you're in the same block, this clobbers your original $var, which produces the warning.

    You note that adding bare blocks around your packages suppresses the warning. That's because $var is a different $var in each block.

      Okay, so without the extra braces, each my $var gets tripped up by the previous definition.

      But with the bare blocks, why does the aaa section associate and print a value for $var while in the bbb section this fails? The code appears identical and independent to me.

      Update: That is, by putting braces around the section in package bbb that newly defines(?) a new lexical variable that also happens to be called $var, why doesn't this get set up independently from the $var of package aaa?

      package bbb; { use strict; use warnings 'all'; my $var = 'second time for var'; sub do_b { print "In 'bbb' var is set to '$var'\n"; } }
      Further update: I suppose it's bad form to do this via an Update, but the following notes don't stand out and they contain the critical pieces (at least for me.)

      chromatic writes: It does declare a new lexical $var over which do_b closes. However, you call the subroutine before the assignment occurs.

      Errto writes: The issue is that the assignment of $var within the block under bbb never happens before you call do_b. Don't think of a line like my $x = somevalue; as a declaration of a variable to be initialized before the program begins. Think of it as a statement that runs when the program gets to it.

      Certainly these "side effects" would not happen if I structured the components of the example more logically, i.e. saved that "main" section until the end. But it's exactly that jumble that leads to the strange (for me) behavior that now lets me grasp the concept. ++ to you and all who have contributed to this thread.

        This is due to closures. With the braces, your first sub, do_a is defined within the lexical scope that sets $var to 'first var'. In other words:

        { my $var = 'first var'; # sets $var for this block # defines a sub IN this block, so gets this $var sub do_a { print "In 'aaa' var is set to '$var'\n"; } }

        Because subroutine names are available globally, do_a can be called from anywhere, but gets the $var defined in its lexical block.

        Similarly, do_b is defined in a block where $var is set to nothing, and do_c is in a block with no $var at all.

Re: Scope, package, and 'my' variables
by Fletch (Chancellor) on Jan 04, 2005 at 18:10 UTC

    Without the curlies you've got multiple declarations of the same name in the same scope (the top level file lexical scope); with them you've got separate declarations in separate lexical scopes (the blocks) and they're not visible outside the containing scope. This has nothing to do with what the current package at declaration time. Lexical variables live outside the global (package) namespaces.

    Update: See Coping with Scoping.

Re: Scope, package, and 'my' variables
by dragonchild (Archbishop) on Jan 04, 2005 at 18:12 UTC
    Changing packages doesn't change lexical scope. Only squiggly brackets do that1. But, the good news is that package declarations don't need squiggly brackets to work. So, if you want to declare a variable at the top of your file and have it be a file-scoped lexical, it will work just like (it seems) you want.

    1. That's not exactly true, but it's a good rule of thumb.

    Being right, does not endow the right to be rude; politeness costs nothing.
    Being unknowing, is not the same as being stupid.
    Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
    Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

Re: Scope, package, and 'my' variables
by johnnywang (Priest) on Jan 04, 2005 at 18:13 UTC
    That is the correct/expected behavior.
    To me it would seem that if I'm getting a message about a new 'my' dec +laration of a variable, that the new declaration would be ignored and + the previous value would still be in effect
    I don't think any programming language behaves this way if it allows it. The latter declarations always overwrite the earlier ones. In perl, lexical scoped variables are not affected by packages.
Re: Scope, package, and 'my' variables
by ikegami (Pope) on Jan 04, 2005 at 18:16 UTC

    There's such thing as "a lexical (my var) in package 'aaa'", as implied. Lexicals are not package-scoped, they are block scoped. That's the whole idea behind them. All three of your $var variables are in the same block, which is why the second and third one hide the previous ones. Block scoping is determined by file and by curlies (and probably by some less obvious things), but not by packages.

    If you want package variables, use our $var or use vars qw($var);.

Re: Scope, package, and 'my' variables
by davido (Archbishop) on Jan 04, 2005 at 18:22 UTC

    If you run your code through perl -MO=Xref mytest.pl, you'll get the following output...

    ----- unneeded portion of output not shown ----- Package aaa &do_a s14 Package bbb &do_b s24 Package ccc &do_c s25 Subroutine (main) Package (lexical) $var i10, i21, i34, 27 Package aaa &do_a &23 Package bbb &do_b &24 Package ccc &do_c &25 Subroutine aaa::do_a Package (lexical) $var 13 Subroutine bbb::do_b Package (lexical) $var 37 Subroutine ccc::do_c Package (lexical) $var 48 mytest.pl syntax OK

    The important part of all that is:

    Package (lexical) $var i10, i21, i34, 27

    That's saying that $var is being declared in line 10, 21, and 34. ...and used in 27. This confirms what others have previously mentioned in this thread; that packages don't create their own lexical scopes. Files create lexical scope, and curly brackets do. So it's common to think of a package as its own lexical scope, since it's also common (though not a requirement) for packages to live alone in a file. But you can't rely on that logic because multiple packages in the same file reside in the same scope.

    Update: On a side note, I do think that B::Xref's output is a little misleading by saying, "Package (lexical) $var .....". It seems that it ought to say something more akin to "File (lexical) $var" or "Block (lexical) $var ..."

    I'm kind of interested in hearing the reason for why it does what it does.


    Dave

      I'm kind of interested in hearing the reason for why it does what it does.

      Probably because the lexical pad is just another stash like those used for packages. I agree that the output is a little misleading, but anyone using B::Xref should know enough to not get confused :-)

Re: Scope, package, and 'my' variables
by demerphq (Chancellor) on Jan 04, 2005 at 18:32 UTC

    Since it seems (when i started this at least) that nobody else has explained what the "lexical" part of "lexical scoping" means I might as well give it a go: the term "lexical" is used because the scoping is based on the lexical context of the declaration of the var. Lexical: "Of or relating to the vocabulary, words, or morphemes of a language." So this means that scope of a lexical is the smallest enclosing block in the file the declaration occurs within. OTOH, package statements have NO EFFECT on lexical variables. Perl doesn't care at all about packages and namespaces when dealing with lexicals. Consider:

    #!perl -l my $foo='$foo'; package Bar; print $foo; #prints '$foo' package Baz; print $foo; #prints '$foo'

    Perl has a different type of variable that are called variously "dynamically scoped" or "globals" or "package variables" or the like. These variables are NOT scoped lexically. (In fact its arguable they arent scoped at all, depending on your definition of scoped.). Traditionally when not using strict any variables mentioned are assumed to be package variables. When using strict any variables that strict isnt specifically informed about (using use vars or our $var;) and isnt declared with a "my" are assumed to be lexicals that you have mistyped and thus throw an error.

    The major differences between these two type of variables are as follows:

    1. package variables dont need to be declared _ever_. use vars and our actually arent declarations in the traditional sense, they are actually pragmatta that alter the behaviour of strict, they dont alter the behaviour of package variables at all.
    2. lexical variables MUST ALWAYS be declared. If you havent declared it with a my then it isnt a lexical.
    3. lexical variables are faster than package variables. With deeply nested namedspaces and FQ notation much faster.
    4. package variables are dynamically scoped. This means that you can use the local keyword for them.
    5. package variables require more space
    6. package statements change how package variables are dealt with Perl, package statements have nothing at all to do with lexical variables.

    What is really cool is that lexicals can be "converted" into package variables, but package variables cannot be "converted" into lexicals:

    *main::package_var=\(my $lexical_var); $lexical_var='foo'; print $main::package_var; #prints 'foo'

    update: fixed a typo where i said "lexical" and meant "package".

    ---
    demerphq

Re: Scope, package, and 'my' variables
by revdiablo (Prior) on Jan 04, 2005 at 18:36 UTC

    Others have explained this behavior by pointing out that lexical variables are scoped to the current block. That's right, but you might be wondering how that determination is made. I like to think of it as an entirely physical process. It doesn't matter what abstract delineations occur (e.g., different packages, BEGIN blocks, END blocks), the physical delineations are what matter for lexical variables. Just to drive the point home:

    my $x = 1; BEGIN { $x = 2; } print $x; # 1
    BEGIN { my $x = 1; } print $x; # undefined, failure under strict.pm
    my $x = 1; { package foo; $x = 2; } print $x; # 2
    my $x = 1; { package foo; my $x = 2; } print $x; # 1

    Hopefully these examples help you understand the point I'm trying to make. That is, the runtime order of the code doesn't matter to lexical variables, nor does the abstract boundaries of packages. The only thing that matters is where in the source code the variables are scoped and used.

      Thanks for the example. Minor quibble, perhaps it's my 5.8 system, but that second print statement does not fail as undefined. Instead it prints '1'.

      #!/usr/bin/perl -w use strict; my $x = 1; BEGIN { $x = 2; } print $x, "\n"; # 1 BEGIN { my $x = 1; } print $x, "\n"; # (sic: ) undefined, failure under strict.pm # Apr 30, 05: Actually, mine doesn't fail and prints '1' my $x = 1; # 'my' generates a 'masks declaration' warning { package foo; $x = 2; } print $x, "\n"; # 2 my $x = 1; # 'my' generates a 'masks declaration' warning { package foo; my $x = 2; } print $x, "\n"; # 1

        Each example must be run separately. You're getting the value of $x defined from the previous test. If you run the 2nd one by itself, however:

        $ perl -le ' BEGIN { my $x = 1; } print defined $x ? "defined" : "undefined";' undefined

        And with strict:

        $ perl -Mstrict -le ' BEGIN { my $x = 1; } print $x;' Global symbol "$x" requires explicit package name at -e line 2. Execution of -e aborted due to compilation errors.
Re: Scope, package, and 'my' variables
by rtwingfield (Acolyte) on Jan 05, 2005 at 00:33 UTC
    You can export symbols from modules by using Exporter(). For example, in the automatically executed BEGIN subroutine, the Exporter will export the subroutine, print_hidden_param_fields and the six vars associated with it. The subroutine can then be called without qualification reference to the used module, and the vars are globaly available without qualification.

    BEGIN { use Exporter(); @ISA=qw(Exporter); @EXPORT=qw(&print_hidden_param_fields $host_name $db_name $userid $passwd $table $pkey); } use vars qw($host_name $db_name $userid $passwd $table $pkey);

    Take a look at Steven Holzner, "Exporting Symbols from Modules by Default", Perl Black Book, Coriolis Open Press, 1999, p. 846-847.

Re: Scope, package, and 'my' variables
by broquaint (Abbot) on Jan 05, 2005 at 02:29 UTC
    As others have noted, package declarations bear no relation to the scope and scoping of lexical variables. To clear up how lexical variables and the scopes they live in behave I wrote a node entitled Lexical scoping like a fox which I hope is of help.
    HTH

    _________
    broquaint

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://419327]
Approved by jfroebe
Front-paged by jfroebe
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (4)
As of 2014-10-26 08:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    For retirement, I am banking on:










    Results (152 votes), past polls