Use __SUB__ to get a reference to the current subroutine

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

One thought on “Use __SUB__ to get a reference to the current subroutine”

  1. 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)

Comments are closed.