Search code examples
perlscope

Two occurrences of a variable declared with 'my' but in two different packages in the same file


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?


Solution

  • 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