I haven’t coded anything in Perl for a long time. Now I have started again and came across an interesting situation when coding two packages within a single ‘.pm’ file. Until now I thought that if I define two packages in a file (e.g. ConfigData and RuntimeData), I can define a variable (declared with ‘my’) with the same name (e.g. my $instance) for each package without conflicts. As an example, here is a minimal code to illustrate this:
package Jabs::ConfigData;
use strict;
use warnings;
my $instance;
sub new {
my ($class) = @_;
unless (defined $instance) {
$instance = bless {}, $class;
}
return $instance;
}
1; # End of 'ConfigData'
package Jabs::RuntimeData;
use strict;
use warnings;
my $instance;
sub new {
my ($class) = @_;
unless (defined $instance) {
$instance = bless {}, $class;
}
return $instance;
}
1; # End of 'RuntimeData'
I called perl -c test2.pm and got the following message as feedback:
"my" variable $instance masks earlier declaration in same scope at test2.pm line 27.
test2.pm syntax OK
Now it is not clear to me why the scope should be the same. Because ‘my $instance is defined in two different packages.
I am using Ubuntu 24.04 LTS and Perl5 (revision 5 version 38 subversion 2)
Can someone perhaps provide me with an explanation for my comprehension problem?
2
Answers
The related perldoc -f my says:
The package keyword in the form of
package NAME
does not include such a scope. Although the documentation for package mentions you can declare a package with a block, e.g.package NAME BLOCK
. At the bottom is my demonstration of such blocks.perldoc perlmod elaborates:
Outputs:
The short answer is that the package variables and lexical variables are two separate variable tracking systems that have nothing to do with each other.
A package variable is effectively global. It exists at all times and places in the program as long as you know the fully-qualified package name (such as
main::foo
). Thepackage
statement merely changes the default package to use. Thelocal
temporarily replaces the value of package variable in a scope (containing block or file).The lexical variables are completely controlled by scope (containing block or file), that contains the declaration (
my
).In your case, both instances of
my $instance
appear in the same scope (the file).But, it looks like you are trying to create two singleton classes where you either return the thing you already created or create it on first use.
Perl v5.10’s
state
lets you move that variable into the subroutine. That’s a persistent lexical variable. And, the//
(defined-or) let’s you use a binary assignment to make things simple:You can do the same thing prior to v5.10 by defining your
new
inside a scope that contains the$instance
. Now that$instance
only exists in that scope: