How can I inline Perl subroutines?

Lazer picture Lazer · Nov 2, 2010 · Viewed 7.4k times · Source

I am reading Code Complete 2, and one of the points mentioned is about creating subroutines even for operations that seem too simple to have their own subroutines, and how that can be helpful.

I know I can inline functions in C and C++ using the inline keyword. But I never came across a way to inline subroutines in Perl.

Is there a way to tell the Perl interpreter to inline the subroutine calls (or why not)?

Answer

Sinan Ünür picture Sinan Ünür · Nov 2, 2010

Constant subroutines, i.e. subroutines with an empty prototype and constant return value, are inline. That is how the constant pragma defines constants:

sub five() { 5 }

would be inlined if it is seen before its first use.

Otherwise, Perl allows subroutines to be dynamically redefined at run time, so inlining is not suitable.

For subroutines that always return the same value given the same inputs, you can use memoization.

Chapter 13 of Programming Perl provides some information on the optimization steps taken by perl.

This is called constant folding. Constant folding isn't limited to simple cases such as turning 2**10 into 1024 at compile time. It also resolves function calls -- both built-ins and user-declared subroutines that meet the criteria from the section "Inlining Constant Functions" in Chapter 6, Subroutines. Reminiscent of FORTRAN compilers' notorious knowledge of their own intrinsic functions, Perl also knows which of its own built-ins to call during compilation. That's why if you try to take the log of 0.0 or the sqrt of a negative constant, you'll incur a compilation error, not a run-time error, and the interpreter is never run at all.

See also perldoc perlguts.

You can see the effect of constant-folding yourself:

#!/usr/bin/perl

use strict; use warnings;

sub log_ok () { 1 }

if ( log_ok ) {
    warn "log ok\n";
}
perl -MO=Deparse t.pl

Output:

sub log_ok () { 1 }
use warnings;
use strict 'refs';
do {
    warn "log ok\n"
};
t.pl syntax OK

Here, constant folding led to the replacement of the if block with a do block because the compiler knew that log_ok would always return a true value. On the other hand, with:

#!/usr/bin/perl

use strict; use warnings;

sub log_ok () { 0.5 > rand }

if ( log_ok ) {
    warn "log ok\n";
}

Deparse output:

sub log_ok () {
    use warnings;
    use strict 'refs';
    0.5 > rand;
}
use warnings;
use strict 'refs';
if (log_ok) {
    warn "log ok\n";
}
t.pl syntax OK

A C compiler might have replaced the if (log_ok) with if ( 0.5 > rand ). perl does not do that.