If I have a really long package name, I can alias that package by making an entry in the symbol table:
BEGIN {
# Make "Alias" be an alias for "Some::Really::Long::Package";
*Alias:: = \*Some::Really::Long::Package::;
# Equivalent to:
# *main::Alias:: = \*Some::Really::Long::Package::;
}
This is what something like Package::Alias
does for you internally. However, this stinks because it mucks with the main
package. How can I make the alias only affect the current package, and be able to use just the alias within the package? I tried changing the alias definition to
*Short::Alias:: = \*Some::Really::Long::Package::;
But then I have to use Short::Alias->myMethod()
instead of just Alias->myMethod()
.
use strict;
use warnings;
package Some::Really::Long::Package;
sub myMethod {
print "myMethod\n";
}
package Short;
BEGIN {
# Make "Alias" be an alias for "Some::Really::Long::Package";
*Short::Alias:: = \*Some::Really::Long::Package::;
}
# I want this to work
Alias->myMethod();
package main;
# I want this to not work
Alias->myMethod();
Bonus points if both Alias->myMethod()
and Alias::myMethod()
work in the Short
package, and not in main
.
Since you don't want to modify the symbol table of main
, you could create a "package-local" alias with
package Short;
use constant Alias => 'Some::Really::Long::Package'; # create alias
Alias->myMethod(); # correctly calls myMethod() of package Some::Really::Long::Package
or alternatively
package Short;
sub Alias { Some::Really::Long::Package:: } # create alias
Alias->myMethod(); # correctly calls myMethod() of package Some::Really::Long::Package
Both examples should work as intended. Consequently, any attempt to call Alias->myMethod()
from package main
will obviously fail with
Can't locate object method "myMethod" via package "Alias" (perhaps you forgot to load "Alias"?)
because the symbol table %main::
or %::
has no such entry called Alias::
.
Due to the fact that you have several package
calls in one file, you can also create $alias
to reference Some::Really::Long::Package
. Then you can limit the scope of $alias
to the package Short
to make it inaccessible from other places:
package Short;
{
my $alias = Some::Really::Long::Package::; # create alias
$alias->myMethod(); # correctly calls myMethod() of package Some::Really::Long::Package
}
EDIT (as response to the edited question):
The updated question is:
Can both
Alias->myMethod()
andAlias::myMethod()
work in theShort
package but not inmain
?
I don't think so.
There are several options to make it work with the ->
syntax but not with the ::
. This is because perl seems to assume that a bareword like Alias
followed by the package separator ::
represents the package Alias
in the package main
:
package Short;
Alias::myMethod(); # if you call myMethod(), you actually call it ...
::Alias::myMethod(); # ... like this, which is equivalent ...
main::Alias::myMethod(); # ... to this
All three calling options are equivalent, which demonstrates an important fact. If perl encounters something like Foo::
, it starts looking in the package main
first and not from the current (relative) location. So if I'm not missing something here, you can not use Alias::myMethod()
without adding Alias::
to main
.
This is what something like
Package::Alias
does for you internally. However, this stinks because it mucks with themain
package.
Now, what I described above would also explain why modules like Package::Alias
modify your main
package, because there seem to be no way to avoid it.