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 writingPackage->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 namespaceFoo
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 aboutFoo
here. So if you have a sub calledFoo
, and it will call that sub. If you have a constant namedFoo
, it will be used.In summary,
Foo::->method
always means"Foo"->method
.Foo->method
usually means"Foo"->method
.Foo->method
could also meanFoo()->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 usingFoo()->method
).By using
Foo::
, you get better diagnostics if you forget to load the module.You get
instead of
Did I say better? That's just noisier to me.