package variable scope in module subroutine

21,982

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:

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'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;

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'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.

Share:
21,982
Admin
Author by

Admin

Updated on July 09, 2022

Comments

  • Admin
    Admin almost 2 years

    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 used modules are evald 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.

  • yonetpkbji
    yonetpkbji over 10 years
    Excellent explanation and examples, solved and understood all my problems as a result. thanks
  • ShooShoSha
    ShooShoSha over 4 years
    Searched for answer to accessing module variables, learned more about variable scoping. Good answer +1