1

I'm very new to perl so you'll have to excuse my ignorance.

I'm working on a legacy project. I don't have a dedicated IDE, I'm using PHPStorm with a dedicated Perl plugin. When hovering over a new keyword I'm getting a warning Using of fancy calls is not recommended, use TCO::AEMAP->new().

The code in question is

my $aemapper = new TCO::AEMAP();

Basically it's suggesting doing

my $aemapper = TCO::AEMAP->new();

Is there any merit to this claim or is it simply more of a convention? I can't find much on google since I'm not exactly sure what to look for.

Andrei
  • 3,434
  • 5
  • 21
  • 44
  • 1
    I don't see why it would say "fancy". There is nothing fancy about the old style syntax. I wonder what linter this thing is using. – simbabque Jan 22 '20 at 09:43

1 Answers1

5

The new Foo version is called indirect object syntax. It's an old-fashioned way of calling the constructor on a package, and it's discouraged in modern Perl. Here's a partial quote of the relevant section in perldoc.

We recommend that you avoid this syntax, for several reasons.

First, it can be confusing to read. In the above example, it's not clear if save is a method provided by the File class or simply a subroutine that expects a file object as its first argument.

When used with class methods, the problem is even worse. Because Perl allows subroutine names to be written as barewords, Perl has to guess whether the bareword after the method is a class name or subroutine name. In other words, Perl can resolve the syntax as either File->new( $path, $data ) or new( File( $path, $data ) ) .

To parse this code, Perl uses a heuristic based on what package names it has seen, what subroutines exist in the current package, what barewords it has previously seen, and other input. Needless to say, heuristics can produce very surprising results!

Older documentation (and some CPAN modules) encouraged this syntax, particularly for constructors, so you may still find it in the wild. However, we encourage you to avoid using it in new code.

The alternative is calling new as a class method on a package with the arrow, as in Foo->new. The arrow -> does three things:

  1. It looks up what's on its left-hand side. In this case, the bareword Foo looks looks like a package name. So Perl will see if it knows a package (or namespace) with that name.
  2. It calls the method on the right-hand side of the arrow in that package it's just found.
  3. It passes in the thing that's on the right, which in our case is Foo, the package name, as the first argument. That's why in the method declaration you will see my ($class, @args) = @_ or similar.

For all other object oriented calls, it's typical to use the arrow syntax. But there is lots of old code around that uses indirect object syntax for new, and especially older modules on CPAN still use it in their documentation.

Both work, but the indirect object syntax is discouraged. Use Foo->new for new code.

simbabque
  • 53,749
  • 8
  • 73
  • 136
  • Thanks for the reply. I'll stick to the old styling since all of the project uses that. I find consistency a lot better. – Andrei Jan 22 '20 at 09:56
  • Re "*The alternative is calling new as a class method on a package*", They both do that. Just two different syntax for it. – ikegami Jan 22 '20 at 10:01
  • 1
    @Andrei, The old style is error-prone and leads to very weird error messages when you do something wrong. Please don't. Consistency is good. But consistency is no excuse for doing bad things. – ikegami Jan 22 '20 at 10:02
  • 1
    While I fully agree with you I simply can't go changing it through the whole project. Leaving aside the fact that it's quite big it's also stable. I highly doubt my merge request would get approved and no amount of me protesting will help. – Andrei Jan 22 '20 at 10:05
  • 1
    @Andrei, I didn't say to go change everything. "If it ain't broke." But going forward, new method calls should use `$invocant->method` instead of `method $invocant`. – ikegami Jan 22 '20 at 10:06
  • Well, I can at least bring it into discussion. See where that leads. – Andrei Jan 22 '20 at 10:07
  • @Andrei, What about methods call where the invocant is an object. Do you use indirect notation for those? (`foo $aemapper` or `$aemapper->foo`?) – ikegami Jan 22 '20 at 11:45
  • 1
    Also note that [it's planned to allow disabling indirect syntax](https://github.com/Perl/perl5/pull/17477) – Grinnz Jan 22 '20 at 15:44
  • @Grinnz, Awesome! (Left a comment at the linked document.) – ikegami Jan 22 '20 at 22:00
  • @Grinnz I don't think that removing that syntax is a great progress; even with `Foo->new` its not clear just by looking at it if the `Foo::new` method will be called or something else: `package Foo{sub new{}} sub Foo {bless[],"Bar"} Foo->new` –  Jan 23 '20 at 01:11
  • 1
    @mosvy There are many unclear parsing rules, and many of them are caused by the existence of this syntax. Indirect syntax has the exact same ambiguity with imported subs according to https://stackoverflow.com/questions/58263206/how-does-perl-parse-unquoted-bare-words. – Grinnz Jan 23 '20 at 01:17