Reputation:
How do I change the value of a variable in the package used by a module so that subroutines in that module can use it?
Here's 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();
output:
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
to be the same since the package of the subroutine is testmodule
.
I guess this has something to do with the way use
d modules are eval
d as if in a BEGIN
block, but I'd like to understand it better.
I was hoping to set the value of the variable from the main script and use it in the module's subroutine without using the fully-qualified name of the variable.
Upvotes: 10
Views: 23153
Reputation: 107030
As you found out, when you use my
, you are creating a locally scoped non-package variable. To create a package variable, you use our
and not my
:
my $foo = "this is a locally scoped, non-package variable";
our $bar = "This is a package variable that's 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
When you don't put use strict
in your program, all variables defined are package variables. That's why when you don't put it, it works the way you think it should and putting it in breaks your program.
However, as you can see in the following example, using our
will solve your dilemma:
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's bar value!";
sub testme {
# $foo is a locally scoped, non-package variable. It's 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;
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's bar";
testme
And, the output is:
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's bar value!"
The value of bar is "This is the package's 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's bar"
The value of bar is "This is the NEW value for the package's bar"
The error message you're getting is the result of $foo
being a local variable, and thus isn't visible inside the package. Meanwhile, $bar
is a package variable and is visible.
Sometimes, it can be a bit tricky:
if ($bar -eq "one") {
my $foo = 1;
}
else {
my $foo = 2;
}
print "Foo = $foo\n";
That doesn't work because $foo
only bas a value inside the if
block. You have to do this:
my $foo;
if ($bar -eq "one") {
$foo = 1;
}
else {
$foo = 2;
}
print "Foo = $foo\n"; #This works!
Yes, it can be a bit to get your head wrapped around it initially, but the use of use strict;
and use warnings;
is now de rigueur and for good reasons. The use of use strict;
and use warnings;
probably has eliminated 90% of the mistakes people make in Perl. You can't make a mistake of setting the value of $foo
in one part of the program, and attempting to use $Foo
in another. It's one of the things I really miss in Python.
Upvotes: 14
Reputation:
After reading Variable Scoping in Perl: the basics more carefully, I realized that a variable declared with my
isn't in the current package. For example, in a simple script with no modules if I declare my $var = "hello"
$main::var
still doesn't have a value.
The way that this applies in this case is in the module. Since my $greeting
is declared in the file, that hides the package's version of $greeting
and that's the value which the subroutine sees. If I don't declare the variable first, the subroutine would see the package variable, but it doesn't get that far because I use strict
.
If I don't use strict
and don't declare my $greeting
, it works as I would have expected. Another way to get the intended value and not break use strict
is to use our $greeting
. The difference being that my declares a variable in the current scope while our declares a variable in the current package.
Upvotes: 9