Tutorial :What does __PACKAGE__->{foo} mean?



Question:

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?


Solution:1

__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.


Solution:2

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'.


Solution:3

__PACKAGE__ is a hash. This syntax accesses a keyed value.


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »