When should I use the & to call a Perl subroutine?
Asked Answered
M

4

55

I have heard that people shouldn't be using & to call Perl subs, i.e:

function($a,$b,...);
# opposed to
&function($a,$b,...);

I know for one the argument list becomes optional, but what are some cases where it is appropriate to use the & and the cases where you should absolutely not be using it?

Also how does the performace increase come into play here when omitting the &?

Maleate answered 28/8, 2009 at 14:32 Comment(0)
F
38

IMO, the only time there's any reason to use & is if you're obtaining or calling a coderef, like:

sub foo() {
    print "hi\n";
}

my $x = \&foo;
&$x();

The main time that you can use it that you absolutely shouldn't in most circumstances is when calling a sub that has a prototype that specifies any non-default call behavior. What I mean by this is that some prototypes allow reinterpretation of the argument list, for example converting @array and %hash specifications to references. So the sub will be expecting those reinterpretations to have occurred, and unless you go to whatever lengths are necessary to mimic them by hand, the sub will get inputs wildly different from those it expects.

I think mainly people are trying to tell you that you're still writing in Perl 4 style, and we have a much cleaner, nicer thing called Perl 5 now.

Regarding performance, there are various ways that Perl optimizes sub calls which & defeats, with one of the main ones being inlining of constants.

There is also one circumstance where using & provides a performance benefit: if you're forwarding a sub call with foo(@_). Using &foo is infinitesimally faster than foo(@_). I wouldn't recommend it unless you've definitively found by profiling that you need that micro-optimization.

Fokker answered 28/8, 2009 at 14:35 Comment(5)
Could you please expand on the part about "non-default call behavior"?Thirlage
Except, &$x() is not really the best way to call a code ref; you should probably just dereference it, like any other ref: $x->().Dunford
The only time I use & in a call is for AUTOLOAD. The purpose isn't optimization, though, it's to clean up the call stack should anyone want to do a backtrace.Childers
Another corollary of & disabling prototype checking: If you have a function prototyped to take a coderef as its 1st parameter (a la map()/grep()), and you want to pass that function a coderef in a scalar variable, then you must use & in the call. If you don't, Perl will complain because it expects either the name of a function or a brace-enclosed in-place function as the first argument.Plainsman
Robert... the coderef-deref was added by me (with Chip Salzenberg's help) in Perl 5.004. Some of the legacy docs were written before that.Pargeting
D
58

I'm a frequent abuser of &, but mostly because I'm doing weird interface stuff. If you don't need one of these situations, don't use the &. Most of these are just to access a subroutine definition, not call a subroutine. It's all in perlsub.

  1. Taking a reference to a named subroutine. This is probably the only common situation for most Perlers:

     my $sub = \&foo;
    
  2. Similarly, assigning to a typeglob, which allows you to call the subroutine with a different name:

     *bar = \&foo;
    
  3. Checking that a subroutine is defined, as you might in test suites:

     if( defined &foo ) { ... }
    
  4. Removing a subroutine definition, which shouldn't be common:

     undef &foo;
    
  5. Providing a dispatcher subroutine whose only job is to choose the right subroutine to call. This is the only situation I use & to call a subroutine, and when I expect to call the dispatcher many, many times and need to squeeze a little performance out of the operation:

     sub figure_it_out_for_me {
        # all of these re-use the current @_
          if( ...some condition... ) { &foo     } 
       elsif( ...some other...     ) { &bar     }
       else                          { &default }
       }
    
  6. To jump into another subroutine using the current argument stack (and replacing the current subroutine in the call stack), an unrare operation in dispatching, especially in AUTOLOAD:

     goto ⊂
    
  7. Call a subroutine that you've named after a Perl built-in. The & always gives you the user-defined one. That's why we teach it in Learning Perl. You don't really want to do that normally, but it's one of the features of &.

There are some places where you could use them, but there are better ways:

  1. To call a subroutine with the same name as a Perl built-in. Just don't have subroutines with the same name as a Perl built-in. Check perlfunc to see the list of built-in names you shouldn't use.

  2. To disable prototypes. If you don't know what that means or why you'd want it, don't use the &. Some black magic code might need it, but in those cases you probably know what you are doing.

  3. To dereference and execute a subroutine reference. Just use the -> notation.

Derek answered 28/8, 2009 at 19:37 Comment(3)
would you really want to do defined &foo, seems like __PACKAGE__->can('foo') is more "modern"? I'd be interested in opinionsBuckles
can doesn't tell you if a subroutine is defined. It tells you if a subroutine called can wants you to think it's defined, even if it's not.Derek
Also, ->can follows inheritance. Doesn't tell you if the subroutine is actually in the current package.Pargeting
F
38

IMO, the only time there's any reason to use & is if you're obtaining or calling a coderef, like:

sub foo() {
    print "hi\n";
}

my $x = \&foo;
&$x();

The main time that you can use it that you absolutely shouldn't in most circumstances is when calling a sub that has a prototype that specifies any non-default call behavior. What I mean by this is that some prototypes allow reinterpretation of the argument list, for example converting @array and %hash specifications to references. So the sub will be expecting those reinterpretations to have occurred, and unless you go to whatever lengths are necessary to mimic them by hand, the sub will get inputs wildly different from those it expects.

I think mainly people are trying to tell you that you're still writing in Perl 4 style, and we have a much cleaner, nicer thing called Perl 5 now.

Regarding performance, there are various ways that Perl optimizes sub calls which & defeats, with one of the main ones being inlining of constants.

There is also one circumstance where using & provides a performance benefit: if you're forwarding a sub call with foo(@_). Using &foo is infinitesimally faster than foo(@_). I wouldn't recommend it unless you've definitively found by profiling that you need that micro-optimization.

Fokker answered 28/8, 2009 at 14:35 Comment(5)
Could you please expand on the part about "non-default call behavior"?Thirlage
Except, &$x() is not really the best way to call a code ref; you should probably just dereference it, like any other ref: $x->().Dunford
The only time I use & in a call is for AUTOLOAD. The purpose isn't optimization, though, it's to clean up the call stack should anyone want to do a backtrace.Childers
Another corollary of & disabling prototype checking: If you have a function prototyped to take a coderef as its 1st parameter (a la map()/grep()), and you want to pass that function a coderef in a scalar variable, then you must use & in the call. If you don't, Perl will complain because it expects either the name of a function or a brace-enclosed in-place function as the first argument.Plainsman
Robert... the coderef-deref was added by me (with Chip Salzenberg's help) in Perl 5.004. Some of the legacy docs were written before that.Pargeting
T
20

The &subroutine() form disables prototype checking. This may or may not be what you want.

http://www.perl.com/doc/manual/html/pod/perlsub.html#Prototypes

Prototypes allow you to specify the numbers and types of your subroutine arguments, and have them checked at compile time. This can provide useful diagnostic assistance.

Prototypes don't apply to method calls, or calls made in the old-fashioned style using the & prefix.

The & is necessary to reference or dereference a subroutine or code reference

e.g.

sub foo {
   # a subroutine
}

my $subref = \&foo; # take a reference to the subroutine

&$subref(@args);  # make a subroutine call using the reference.

my $anon_func = sub { ... }; # anonymous code reference
&$anon_func(); # called like this

Protypes aren't applicable to subroutine references either.

The &subroutine form is also used in the so-called magic goto form.

The expression goto &subroutine replaces the current calling context with a call to the named subroutine, using the current value of @_.

In essence, you can completely switch a call to one subroutine with a call to the named one. This is commonly seen in AUTOLOAD blocks, where a deferred subroutine call can be made, perhaps with some modification to @_ , but it looks to the program entirely as if it was a call to the named sub.

e.g.

sub AUTOLOAD {
    ...
    push @_, @extra_args; # add more arguments onto the parameter list
    goto &subroutine ; # change call another subroutine, as if we were never here
}

}

Potentially this could be useful for tail call elimination, I suppose.

see detailed explanation of this technique here

Tipsy answered 28/8, 2009 at 14:39 Comment(1)
You need the & to take a reference to a named subroutine, but not to dereference it. The arrow notation is also available: $some_sub->().Derek
U
2

I've read the arguments against using '&', but I nearly always use it. It saves me too much time not to. I spend a very large fraction of my Perl coding time looking for what parts of the code call a particular function. With a leading &, I can search and find them instantly. Without a leading &, I get the function definition, comments, and debug statements, usually tripling the amount of code I have to inspect to find what I'm looking for.

The main thing not using '&' buys you is it lets you use function prototypes. But Perl function prototypes may create errors as often as they prevent them, because they will take your argument list and reinterpret it in ways you might not expect, so that your function call no longer passes the arguments that it literally says it does.

Ubiety answered 11/3, 2015 at 3:35 Comment(1)
agreed. in a code base that uses it consistently, & can be useful. the only downsides are not allowing prototypes (if you can call that a downside) or the possibility of accidentally saying &foo instead of &foo() or accidentally using it on a constant and suppressing constant inlining. These downsides are not enough to discourage it if you choose.Lasley

© 2022 - 2024 — McMap. All rights reserved.