The scope of a package variable in a modular routine

How to change the value of a variable in the package used by the module so that the routines in this module can use it?

Here is my test case:

testmodule.pm:

package testmodule; use strict; use warnings; require Exporter; our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS); @ISA = qw(Exporter); @EXPORT = qw(testsub); my $greeting = "hello testmodule"; my $var2; sub testsub { printf "__PACKAGE__: %s\n", __PACKAGE__; printf "\$main::greeting: %s\n", $main::greeting; printf "\$greeting: %s\n", $greeting; printf "\$testmodule::greeting: %s\n", $testmodule::greeting; printf "\$var2: %s\n", $var2; } # End testsub 1; 

testscript.pl:

 #!/usr/bin/perl -w use strict; use warnings; use testmodule; our $greeting = "hello main"; my $var2 = "my var2 in testscript"; $testmodule::greeting = "hello testmodule from testscript"; $testmodule::var2 = "hello var2 from testscript"; testsub(); 

exit:

 Name "testmodule::var2" used only once: possible typo at ./testscript.pl line 11. __PACKAGE__: testmodule $main::greeting: hello main $greeting: hello testmodule $testmodule::greeting: hello testmodule from testscript Use of uninitialized value $var2 in printf at testmodule.pm line 20. $var2: 

I expected $greeting and $testmodule::greeting be the same since the testmodule routine testmodule .

I think this is because use d modules are eval d, as if in a BEGIN block, but I would like to better understand it.

I was hoping to set the variable value from the main script and use it in the module routine without using the full variable name.

+7
source share
2 answers

After a more thorough reading of โ€œPerl Variable Scope: Basics,โ€ I realized that the variable declared with my is not in the current package. For example, in a simple script without modules, if I declare my $var = "hello" $main::var , it still does not matter.

The way this applies in this case is in the module. Since my $greeting declared in the file, which hides the package version of $greeting and the value that the routine sees. If I do not declare the variable first, the routine will see the package variable, but it does not go that far, because I use strict .

Unless I use strict and declare my $greeting , it works as I expected. Another way to get the set value and not break use strict is to use our $greeting . The difference is that my declares a variable in the current scope , and our declares a variable in the current package .

+8
source

As you know, when you use my , you create a local non-packet area. To create a package variable, use our , not my :

 my $foo = "this is a locally scoped, non-package variable"; our $bar = "This is a package variable that visible in the entire package"; 

Even better:

 { my $foo = "This variable is only available in this block"; our $bar = "This variable is available in the whole package": } print "$foo\n"; #Whoops! Undefined variable print "$bar\n"; #Bar is still defined even out of the block 

If you do not put use strict in your program, all variables are defined as package variables. Therefore, when you do not install it, it works as it seems to you, and should prevent it from breaking your program.

However, as you can see in the following example, using our will solve your dilemma:

File Local/Foo.pm

 #! /usr/local/bin perl package Local::Foo; use strict; use warnings; use feature qw(say); use Exporter 'import'; our @EXPORT = qw(testme); our $bar = "This is the package bar value!"; sub testme { # $foo is a locally scoped, non-package variable. It undefined and an error say qq(The value of \$main::foo is "$main::foo"); # $bar is defined in package main::, and will print out say qq(The value of \$main::bar is "$main::bar"); # These both refer to $Local::Foo::bar say qq(The value of \$Local::Foo::bar is "$Local::Foo::bar"); say qq(The value of bar is "$bar"); } 1; 

File test.pl

 #! /usr/local/bin perl use strict; use warnings; use feature qw(say); use Local::Foo; my $foo = "This is foo"; our $bar = "This is bar"; testme; say ""; $Local::Foo::bar = "This is the NEW value for the package bar"; testme 

And, output:

 Use of uninitialized value $foo in concatenation (.) or string at Local/Foo.pm line 14. The value of $main::foo is "" The value of $main::bar is "This is bar" The value of $Local::Foo::bar is "This is the package bar value!" The value of bar is "This is the package bar value!" Use of uninitialized value $foo in concatenation (.) or string at Local/Foo.pm line 14. The value of $main::foo is "" The value of $main::bar is "This is bar" The value of $Local::Foo::bar is "This is the NEW value for the package bar" The value of bar is "This is the NEW value for the package bar" 

The error message you receive is the result of $foo , which is a local variable, and therefore does not appear inside the package. Meanwhile, $bar is a package variable and is displayed.

Sometimes it can be a little tricky:

 if ($bar -eq "one") { my $foo = 1; } else { my $foo = 2; } print "Foo = $foo\n"; 

This does not work because $foo contains only the value inside the if block. You must do this:

 my $foo; if ($bar -eq "one") { $foo = 1; } else { $foo = 2; } print "Foo = $foo\n"; #This works! 

Yes, it may be a little to wrap your head around it first, but use use strict; and use warnings; is now exhaustive and for good reason. Using use strict; and use warnings; probably eliminated 90% of the mistakes people make in Perl. You cannot go wrong when setting the value of $foo in one part of the program and try to use $foo in another. This is one of the things that I really missed in Python.

+11
source

All Articles