Control flow

sub#

Declare or define a subroutine.

sub is the keyword that introduces a subroutine. With a NAME and a BLOCK it defines a named subroutine in the current package. Without a BLOCK it is a forward declaration. Without a NAME it is an anonymous sub expression that evaluates to a code reference — sub { ... } is the only form of sub that is actually an expression; the named forms are declarations and return nothing useful.

Synopsis#

sub NAME BLOCK                         # named definition
sub NAME (PROTO) BLOCK                 # with prototype
sub NAME : ATTRS BLOCK                 # with attributes
sub NAME (PROTO) : ATTRS BLOCK         # prototype + attributes

sub NAME;                              # forward declaration
sub NAME (PROTO);                      # forward with prototype

my $ref = sub BLOCK;                   # anonymous, returns code ref
my $ref = sub (PROTO) : ATTRS BLOCK;   # anonymous with proto + attrs

use feature 'signatures';
sub NAME ($x, $y = 0, @rest) BLOCK     # named with signature
my $ref = sub ($x, $y) BLOCK;          # anonymous with signature

What you get back#

The named forms (sub NAME BLOCK, sub NAME (PROTO) BLOCK, etc.) are declarations. They install the subroutine into the current package’s symbol table at compile time and contribute nothing to the surrounding expression. Writing my $x = sub foo { 1 }; is a common mistake — that is two statements glued together, and $x is left undefined.

The anonymous form sub BLOCK is an expression. It evaluates — at the point the expression is reached at runtime, not at compile time — to a code reference closing over the lexical variables in scope. The same sub { ... } expression evaluated twice produces two distinct code references that share nothing:

my @refs = map { sub { $_ } } 1..3;     # three independent closures

Forward declarations (sub NAME; with no block) do nothing at runtime and return nothing. Their purpose is to announce the name to the parser so that later calls to it can parse without parentheses.

Global state it touches#

  • The current package (set by package) determines the fully-qualified name of a named sub. sub foo { } inside package Acme; installs Acme::foo, not main::foo.

  • @_ inside the body holds the argument list (aliased to the caller’s scalars, except when a signature is in effect — see Signatures below). Assigning to @_ as a whole breaks the aliasing for the rest of the call.

  • $_[N] elements are aliases to the caller’s scalars. Modifying $_[0] modifies the caller’s variable; passing a literal and then modifying $_[0] is a fatal error.

  • wantarray inside the body reflects the context the subroutine was called in.

Named definition#

sub greet {
    my ($name) = @_;
    return "Hello, $name";
}

print greet("world"), "\n";            # Hello, world

The body is compiled at compile time. The name is visible from that point in the file onward; forward references inside the same package work because Perl defers method-style and bareword calls.

Redefining a named sub at runtime (eval "sub foo { ... }" or a second sub foo { } in the same package) replaces the previous definition and emits a Subroutine foo redefined warning under use warnings. Suppress it with no warnings 'redefine' for the scope of the redefinition.

Anonymous sub and closures#

sub make_counter {
    my $n = 0;
    return sub { ++$n };
}

my $c = make_counter();
print $c->(), $c->(), $c->(), "\n";    # 123

The inner sub captures $n from its enclosing scope. Each call to make_counter creates a fresh $n and a fresh closure over it.

my @doublers = map { my $k = $_; sub { $k * 2 } } 1..3;
print $doublers[2]->(), "\n";          # 6

Note the intermediate my $k = $_ — closures capture variables, not values, and $_ is shared across the map iterations. Without the copy, every closure would see the last value of $_.

Signatures#

With use feature 'signatures' (on by default under use v5.36 and later), the parameter list appears between the name and the block, and arguments are bound to lexical variables automatically:

use feature 'signatures';

sub add ($x, $y) { $x + $y }

sub greet ($name, $greeting = "Hello") {
    return "$greeting, $name";
}

sub log_all ($level, @msgs) {
    print "[$level] $_\n" for @msgs;
}

Signature forms:

  • $x — required positional parameter.

  • $x = EXPR — optional positional with default; EXPR is evaluated each call when the argument is missing.

  • $x = undef — optional, defaults to undef (useful for documenting that a slot is nullable rather than omitted).

  • @rest / %rest — slurpy, consumes all remaining arguments.

  • $ / @ / % — unnamed placeholder, asserts arity without binding a variable.

Calling with the wrong arity croaks: Too many arguments for subroutine or Too few arguments for subroutine.

Under a signature, @_ still exists but accessing it is a warning under use warnings 'experimental::args_array_with_signatures' in earlier Perls and discouraged in 5.42. Use the signature variables instead.

Prototypes#

sub mypush (\@@) {
    my $aref = shift;
    push @$aref, @_;
}

my @a = (1, 2);
mypush @a, 3, 4;                       # @a is now (1, 2, 3, 4)

Prototypes are a compile-time parser hint, not a type check. They change how call sites are parsed: \@ in the prototype above forces the first argument to be an array and passes a reference to it. See prototype to inspect a sub’s prototype.

Prototypes do nothing when the sub is called via &name(...) or through a code reference. If you want a signature, use use feature 'signatures'; prototypes and signatures can coexist with the :prototype(...) attribute:

use feature 'signatures';
sub each_pair :prototype(\@) ($aref) { ... }

Attributes#

Attributes appear after : and modify how the sub is compiled or registered:

sub critical :lvalue { $state }        # usable on the left of =
sub noop     :method { }               # marked as a method (for some tools)

Common core attributes: lvalue, method, prototype(...), const. Modules like Attribute::Handlers let a package define its own. Unknown attributes are a compile-time error.

Forward declaration#

sub later;                             # announce the name
plan later(3);                         # now parses without parens
sub later { ... }                      # defined later in the file

A forward declaration is only useful to tell the parser that later is a subroutine so that later ARG parses as a call rather than an indirect-object construct or a comma expression. It is not required if you call with parentheses.

Examples#

Named sub, explicit argument unpacking:

sub area {
    my ($w, $h) = @_;
    return $w * $h;
}
print area(3, 4), "\n";                # 12

Anonymous sub passed to a higher-order function:

my @lengths = map { sub { length shift } }->(@_),
              ("alpha", "beta", "gamma");   # not quite — see below

More useful: passing a sub directly:

use List::Util qw(first);
my $first_even = first { $_ % 2 == 0 } 1, 3, 4, 7;   # 4

Implicit return — the value of the last expression is returned:

sub double { $_[0] * 2 }               # no return needed
print double(21), "\n";                # 42

Context-sensitive return:

sub names {
    my @n = qw(alice bob carol);
    return wantarray ? @n : scalar @n;
}

my @all = names();                     # ("alice","bob","carol")
my $n   = names();                     # 3

Modifying caller arguments via @_ aliasing:

sub upcase_in {
    for (@_) { $_ = uc }
}
my $s = "hello";
upcase_in($s);
print $s, "\n";                        # HELLO

Recursion with __SUB__ — a reference to the current sub without naming it:

use feature 'current_sub';
my $fact = sub {
    my $n = shift;
    $n < 2 ? 1 : $n * __SUB__->($n - 1);
};
print $fact->(5), "\n";                # 120

Edge cases#

  • A named sub definition is a statement, not an expression. It contributes nothing to its enclosing expression. my $x = sub foo {}; parses as two statements; $x ends up undef.

  • The sub NAME BLOCK forms are compile-time. The block body is parsed and compiled when the enclosing file or eval is compiled. Side effects inside the block run only when the sub is called, not when it is defined. By contrast, sub BLOCK (anonymous) evaluates at runtime every time the expression is reached, producing a new closure each time.

  • Nested named subs close over nothing useful. A sub defined inside another sub is still installed in the package at compile time and does not capture lexicals from the enclosing call. Each call to the outer sub sees the same inner sub, warped around the first call’s lexicals. Use an anonymous sub for closures.

  • Trailing return is optional but explicit is clearer. Without return, the value of the last expression is returned. If the last statement is a loop or a block, the return value is unspecified — do not rely on it.

  • Assigning to @_ wholesale breaks aliasing. @_ = @_ or @_ = (1, 2) replaces the array and later $_[0] = X no longer reaches the caller.

  • Passing a literal then modifying $_[0] is fatal. upcase_in("x") dies with Modification of a read-only value attempted because $_[0] is aliased to the literal.

  • Redefining a sub emits Subroutine X redefined under use warnings. Wrapping a redefinition requires no warnings 'redefine' for the scope:

    no warnings 'redefine';
    *Foo::bar = sub { ... };
    
  • sub inside a BEGIN block is defined at compile time of the surrounding unit, same as any sub declaration; the BEGIN wrapping does not change the timing of the declaration itself.

  • A prototype after a space gotcha. sub foo ($$) with use feature 'signatures' is parsed as a signature, not a prototype. To attach a prototype under signatures, use sub foo :prototype($$) ($x, $y) { ... }.

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • return — explicit return from a sub; without it the last expression’s value is returned

  • wantarray — inspect the calling context (list / scalar / void) from inside the body

  • caller — information about who called this sub and from where

  • prototype — read back the prototype of a named or anonymous sub

  • __SUB__ — reference to the current sub without naming it; the tool for anonymous recursion

  • my — the usual way to unpack @_ into named lexicals when not using signatures

  • method — class-syntax method declaration; use feature 'class' equivalent of sub for methods