Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does __PACKAGE__->{foo} mean?

Tags:

perl

I'm refactoring a perl module in legacy code, and this is a function from the module:

sub get_user {
    my $user = __PACKAGE__->{user};
    if (!defined $user) {
       # more code
       __PACKAGE__->{user} = $user;
    }
    return $user;
}

This module compiles under use strict. And there's no package variables defined. What does __PACKAGE__->{user} mean?

like image 271
Eugene Yarmash Avatar asked Jul 07 '10 13:07

Eugene Yarmash


2 Answers

__PACKAGE__ is the name of the current package; your code is using it as a symbolic hash reference. So if your package is foo, it is setting $foo::foo{'user'}. This is kind of a strange thing to do; I suspect it may be an error.

Because it's a symbolic reference, it shouldn't be allowed under strict. It seems to be, however, at least when the current package has multiple parts (e.g. Foo::Bar, not just Foo). I wouldn't depend on this bug staying in effect, though.

like image 126
ysth Avatar answered Nov 15 '22 23:11

ysth


use strict;
use warnings;
use 5.012;

{
    package X::Y;

    our $user = 10;
    say $user;

    say __PACKAGE__;

}


--output:--
10
X::Y

The package name may be 'X::Y' but the symbol table for the package is named 'X::Y::' (note the trailing colons). A symbol table is a perl hash, and the keys in the %X::Y:: hash are the global names used in the X::Y package. The corresponding values are the typeglobs for each name:

use strict;
use warnings;
use 5.012;

{
    package X::Y;

    our $user = 10;
    say $user;

    say __PACKAGE__;
    say $X::Y::{user};   #Hash name is %X::Y::


}

--output:--
10
X::Y
*X::Y::user

But the expression in the op:

__PACKAGE__->{user} 

is equivalent to:

'X::Y'->{user}

I fail to see how that line will succeed in retrieving anything from a hash whose name is 'X::Y::' (ends in two colons). And in fact, I get this error:

use strict;
use warnings;
use 5.012;

{
    package X::Y;

    our $user = 10;
    say $user;

    say __PACKAGE__;
    say $X::Y::{user}; 
    say __PACKAGE__->{user};
}

--output:--
10
X::Y
*X::Y::user
Use of uninitialized value in say at 2.pl line 13.

If the code actually creates a hash named %X::Y somewhere, then the code will run without errors:

use strict;
use warnings;
use 5.012;


%X::Y = (); #This hash has nothing to do with the hash named 
            #%X::Y::, which is the symbol table for the 
            #X::Y package.  

$X::Y{user} = 'hello';


{
    package X::Y;

    sub get_user {
        say __PACKAGE__->{user};
    }

    get_user;
}


--output:--
hello

As mentioned in the comment, the %X::Y hash has nothing to do with the X::Y package. In fact, the line:

%X::Y = ();

explicitly declares a variable called Y in the X package. The X package and the X::Y package are two different packages.

And there's no package variables defined

The sub name is a package variable:

use strict;
use warnings;
use 5.012;

{
    package X::Y;

    sub get_user {say 'hello';}

    say $X::Y::{get_user};

}

--output:--
*X::Y::get_user

The fact that a typeglob for the name 'get_user' exists, means that the code uses at least one global variable named 'get_user'.

like image 40
14 revs Avatar answered Nov 15 '22 22:11

14 revs