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?
The related perldoc -f my says:
A my declares the listed variables to be local (lexically) to the enclosing block, file, or eval.
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:
A package statement affects only dynamic global symbols, including subroutine names, and variables you've used local() on, but not lexical variables created with my(), our() or state().
use strict;
use warnings;
use feature 'say';
package Conf { # <-- block start
use strict;
use warnings;
my $instance;
sub new {
my ($class) = @_;
unless (defined $instance) {
$instance = bless {}, $class;
}
$instance->{foo} = "Confs";
return $instance;
}
1;
} # <-- block end END OF CONF
package eData { # <-- block start
use strict;
use warnings;
my $instance;
sub new {
my ($class) = @_;
unless (defined $instance) {
$instance = bless {}, $class;
}
$instance->{foo} = "eDatas";
return $instance;
}
1;
} # <-- block end END OF EDATA
my $c1 = Conf->new; # loads the first $instance
my $c2 = eData->new; # loads the other $instance, different variable and scope
say $c1->{foo};
say $c2->{foo};
Outputs:
Confs
eDatas