I was reading the documentation for the attributes
module and came across a method call notation I've never seen:
use attributes ();
attributes::->import(__PACKAGE__, \$x, 'Bent');
The doc did not provide an explanation for this syntax.
On investigation, it seems Package::->method()
is equivalent to Package->method()
and 'Package'->method()
.
It also seems equivalent to Package::method('Package')
, provided the method is not inherited.
Question 0: Is there any practical reason for using Package::->method()
notation?
Edit: I found if you have a constant with the same name as a package, Package::->method()
calls the package method, whereas Package->method()
calls the method on the constant.
use constant Foo => bless {}, 'Bar'; # or just => 'Bar'
print Foo::->method(); # prints 'Foo method'
print 'Foo'->method(); # prints 'Foo method'
print Foo->method(); # prints 'Bar method'
package Foo;
sub method { 'Foo method' }
package Bar;
sub method { 'Bar method' }
Strangely, with use warnings
, this script will give a "Bareword 'Foo::' refers to nonexistent package" warning but will execute it anyway, which just confuses me more.
Even more strangely, adding the line Foo::method();
before the Foo::->method()
line gets rid of the "Bareword" warning.
Question 1: Can someone please explain what's going on?
For posterity, this is Perl v5.38.0.
Package::->method
is a (very slightly) safer way of writing Package->method
.
This is answered by the documentation. How does Perl parse unquoted bare words? is also relevant.
Foo::
is equivalent to "Foo"
, except it also checks if namespace Foo
exists.
Foo
also means "Foo"
, but only if it doesn't mean anything else. It's exempt from strictures when before ->
, but there's otherwise nothing special about Foo
here. So if you have a sub called Foo
, and it will call that sub. If you have a constant named Foo
, it will be used.
In summary,
Foo::->method
always means "Foo"->method
.Foo->method
usually means "Foo"->method
.Foo->method
could also mean Foo()->method
.From that, we derive the following reasons for using Foo::
:
By using Foo::
, you avoid calling a sub by accident. (This includes constants.)
The chances of this happening are incredibly small in practice. And it's something that would be found in testing, one hopes. But given the rarity of occurrences, it could be confusing were it to ever happen.
By using Foo::
, you signal that it's not a sub call.
But that's already the presumption when you see something of the form Foo->method
. It's more important to signal when it is a sub call (for example, by using Foo()->method
).
By using Foo::
, you get better diagnostics if you forget to load the module.
You get
Bareword "Foo::" refers to nonexistent package at ...
Can't locate object method "method" via package "Foo" (perhaps you forgot to load "Foo"?)` at ...
instead of
Can't locate object method "method" via package "Foo" (perhaps you forgot to load "Foo"?)` at ...
Did I say better? That's just noisier to me.