perlperlop

Perl's "Package::->method()" (colon-colon-arrow) notation


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.


Solution

  • 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,

    From that, we derive the following reasons for using Foo:::