Home > Software design >  When do Perl package variables fall out of scope?
When do Perl package variables fall out of scope?

Time:02-02

From my main program I require a file containing a package, and then call a subroutine from that package:

while($somecondition){
  require( 'people.pm' );
  my $result = PERSON::stuff($args);
}

The PERSON package has multiple subs and some 'our' variables declared:

package PERSON;
our $name;
our ...
sub stuff {
  ...
}

In my understanding of other more object oriented languages you would need to declare a new object instance, maybe with its own constructor/initialization functions to use "package" variables. That doesn't seem to be the case here with Perl.

I'm dealing with legacy code so I don't want to change much, I just want to understand when the package variables ($name) come into existence, and when are they returned to memory from the perspective of the main program.

Would putting a PERSON::stuff() call after the while loop have new package variables? After calling a single function inside a package do the package variables live until the end of the program?

CodePudding user response:

The question mixes up some concepts so let's first address what appears to be the main issue: If a package is require'd inside some scope, what of it outside of that scope?

In short, (dynamical global) symbols from the package are accessible everywhere in the unit in which it is require'd, via their fully qualified names.

Let's try with an example

use warnings;
use strict; 
use feature 'say';

TEST_SCOPE: {
    say "In scope, in ", __PACKAGE__;
    require TestPack;
    #hi();                  # "Undefined subroutine &main::hi called..."
    TestPack::hi();         # ok
    #say $global;           # $global ... who??
    say $TestPack::global;  # ok
    say "Leaving scope\n";
};

say "--- in ", __PACKAGE__;
TestPack::hi();             # ok
say $TestPack::global;      # ok

File TestPack.pm:

package TestPack;

use warnings;
use strict;
use feature 'say';

#use Exporter qw(import);  # This is what one normally does to export symbols
#our @EXPORT_OK = qw(hi);  # (unless the package is a class)

our $global = 7;

sub hi { say "hi from ", __PACKAGE__ }

1;

Note that one needs to use fully qualified names for those dynamic global symbols since they weren't imported. If the package exports symbols and we import some§ then they go into the calling package's namespace so in the example above they'd be available in main::. One cannot access lexical variables in that package (created with my, our, state).

This works the same way if instead of the mere block (named TEST_SCOPE) we introduce another package, and require our TestPack inside of it.

...

package AnotherPack {
    require TestPack;
    ...
    1;
};

...

(That package should be inside a BEGIN block really, what doesn't change the main point here.) Global symbols from TestPack are still accessible in main::, via their fully qualified names. The exported names, which we import along with require, are then available as such in this package, but not in main::.

Comments on the question

  • Package name (PERSON) and the filename for it (person.pm) have to agree. For example, the namespace (==package) Person is defined in the file Person.pm

  • This is about basics related to require-ing a package; it has nothing to do with object-oriented notions. (Even though, a class is firstly a package. See perlootut and perlobj.) Also see Packages in perlmod and our.

  • If you were to use a package that bless-es, the returned object (instance) is (assigned to) a lexical variable. As such, it doesn't exist outside of the scope. The package itself, though, is visible just as shown above but in object-oriented work we don't want to poke at a package's insides, but rather use methods via objects.

    So yes, to work with that package outside of the scope in which it is require-ed you'd need to instantiate an object in that other scope as well. That would still work much like the example above (try!), even though I'd raise questions of such design (see next)

  • This hints at a convoluted design though, bringing in packages inside scopes, at runtime (via require); what is the context? (And I hope it's not really in a while loop.)


Print out the main's symbol table, %main:: (using Data::Dumper for example) and we find

"TestPack::" => *main::TestPack:: 

along with all other symbols from TestPack namespace.


Note that our creates a lexical which is an alias for a package variable, which is accessible.


§ If a package exports symbols and we require the package then we can import by

require Pack::Name;
Pack::Name->import( qw(subname anothername ...) );

CodePudding user response:

zdim's answer gives a very good explanation of how package variables work and can be used. I don't think it directly answers the question of when they fall out of scope though.

Succinctly:

  • Package variables are global static variables, just namespaced so the "global" aspect isn't as terrible.
  • As with any static variable, they are in scope for the entire execution of the program.

You also asked:

In my understanding of other more object oriented languages you would need to declare a new object instance, maybe with its own constructor/initialization functions to use "package" variables. That doesn't seem to be the case here with Perl.

Package variables are fairly unrelated to object-oriented programming in Perl. They are not used for storing instance data. (Except sometimes in the case of inside-out objects, though that's more of an advanced topic.)

  • Related