What if you want to write a recursive subroutine but you don’t know the name of the current subroutine? Since Perl is a dynamic language and code references are first class objects, you might not know the name of the code reference, if it even has a name. Perl 5.16 introduces __SUB__
as a special sequence to return a reference to the current subroutine. You could almost do the same thing without the new feature, but each of those have drawbacks you might want to avoid.
Although __SUB__
looks like __FILE__
, __LINE__
, and __PACKAGE__
, each of which are compile-time directives, the __SUB__
happens at run time so you can use it with subroutines you define later.
First, consider how you’d try to do this without the __SUB__
feature. You could declare a variable to hold a subroutine reference then in a later statement define the subroutine. Since you’ve already declared the variable, you can use it in the definition. Perl won’t de-reference it until you actually run the subroutine, so it doesn’t matter that it’s not a reference yet:
use v5.10; my $sub; $sub = sub { state $count = 10; say $count; return if --$count < 0; $sub->(); }; $sub->();
Your output is a countdown:
10 9 8 7 6 5 4 3 2 1 0
To do that, there are two requirements: the code reference must be stored in a variable, and the variable must already be defined. That’s not always convenient. Not only that, your anonymous subroutine contains a reference to itself, so you’d either have to play games with weak references or just let the reference live forever. Neither of those are attractive.
Rafaƫl Garcia-Suarez solved these problems by creating Sub::Current to give you a ROUTINE
function that returns a reference to the current subroutine, even if it is a named subroutine:
use v5.10; use Sub::Current; sub countdown { state $count = 10; say $count; return if --$count < 0; ROUTINE->(); }; countdown();
You might want to define these code references as a single statement, even you don’t need to. This is useful for inline subroutines where you want to define the code reference in the parameter list:
use v5.10; use Sub::Current; sub run { $_[0]->() }; run( sub { state $count = 10; say $count; return if --$count < 0; ROUTINE->(); } );
You may want to define the subroutine in one statement as a return value:
use v5.10; use Sub::Current; sub factory { my $start = shift; sub { state $count = $start; say $count; return if --$count < 0; ROUTINE->(); } }; factory(4)->();
Using this module has the disadvantage of a CPAN dependency, although a very light one because it’s self contained. There’s another module, Devel::Caller, from Richard Clamp that can can get a code reference from any level in the call stack, including the current level:
use v5.10; use Devel::Caller qw(caller_cv); sub factory { my $start = shift; sub { state $count = $start; say $count; return if --$count < 0; caller_cv(0)->(); } }; factory(7)->();
Perl 5.16 lets you do the same thing without the CPAN module:
use v5.15.6; # until v5.16 is released sub factory { my $start = shift; sub { state $count = $start; say $count; return if --$count < 0; __SUB__->(); } };
As with many new features added since Perl v5.10, you can enable __SUB__
with a use VERSION
statement, as you see in the previous example, or with the feature
pragma and the current_sub
import:
use feature qw(say state current_sub); sub factory { my $start = shift; sub { state $count = $start; say $count; return if --$count < 0; __SUB__->(); } }; factory(7)->();
Things to remember
- Perl v5.16 provides the
__SUB__
directive to return a reference to the currently running subroutine - Import this new feature by requiring the Perl version or through the
feature
pragma - Prior to Perl v5.16, you can do this the same thing with Sub::Current
Not the same thing if perfomance matters.
__SUB__ is almost no-op, while ROUTINE() takes time. If your sub is fast, you can see a huge difference
perl -MBenchmark -E ‘use Sub::Current; Benchmark::timethese(100000000, { native => sub { __SUB__ }, subcur => sub { ROUTINE() } })’
Benchmark: timing 100000000 iterations of native, subcur…
native: 0 wallclock secs ( 0.40 usr + 0.00 sys = 0.40 CPU) @ 250000000.00/s (n=100000000)
subcur: 8 wallclock secs ( 8.60 usr + 0.05 sys = 8.65 CPU) @ 11560693.64/s (n=100000000)