Subroutines#

A subroutine is a named (or anonymous) block of code that takes a list of arguments, runs in a fresh lexical scope, and returns a list of values. Subroutines are the unit of reuse in Perl, the unit of dispatch for object-oriented code, and — through closures — the unit of stateful encapsulation. Almost everything else in the language is built on top of them.

PetaPerl implements the full Perl 5.42 subroutine model: the classic @_-based calling convention, modern signatures, the prototype mechanism that controls call-site parsing, lexical and package scoping (my, our, local, state), closures, the attribute system (:lvalue, :method, :prototype(...)), recursion with goto &sub tail calls, and the special compile- and-run-time blocks (BEGIN, END, INIT, CHECK, UNITCHECK).

This reference is split into one page per topic. The @_ aliasing rule lives with arguments, the closure-over-loop-var pitfall lives with scoping, the parser-level effects of prototypes live with prototypes — so each page can be read and returned to without sweeping context.

Choose a topic#

  • Declarationsub NAME { ... }, anonymous subs, forward declarations, code references, the & sigil and what predeclaration buys you.

  • Arguments and @_ — the aliasing rule, the unpacking idiom, named-arg conventions, shift defaults, the chomp(@lines) legitimate use of aliasing, and the $_[0] = ... trap.

  • Return values — explicit return, implicit last-expression, list-flattening on return, void-context shortcuts, and the difference between return; and return undef;.

  • Scoping: my, our, local, state — pad lifetime, closures, the closure-over-loop-variable surprise, when local is the right tool, and what state actually means.

  • Prototypes — what they do (call-site parsing), what they don’t (runtime checks), the (\@) vs (@) difference, the () constant-fold prototype, and why most modern code shouldn’t reach for them.

  • Signatures — the modern syntax from 5.20+ stable in 5.36, with positional, optional, and slurpy parameters; defaults; named parameters via slurpy hash; and how signatures interact with (and don’t replace) prototypes.

  • Recursion — depth limit, mutual recursion, goto &fn for tail calls, __SUB__ for anonymous self-reference, trampolines.

  • Lvalue subs and context:lvalue semantics, wantarray, the void-scalar-list three-way switch, and the standard ”return early in void context“ pattern.

  • Attributes:method, :lvalue, :prototype(...), :const, third-party attributes, and how the four attribute-related steps (parse, register, store, query) compose.

Defining a sub vs. calling a sub#

The two halves of the subroutine system are mostly orthogonal:

  • Definition is a declaration plus a body. The declaration fixes the name (or makes the sub anonymous), the optional prototype or signature, the optional attributes. The body is a block of statements with its own pad.

  • Call turns a list of expressions into the new pad’s @_ (or signature variables), runs the body, and collects whatever the body returned in the caller’s context.

Almost every ”subtle“ subroutine question is a question about one side or the other. Prototypes affect calls only, not definitions; signatures affect what the body sees, not how the caller writes the call; attributes affect how the defined sub is treated by the runtime.

The classic vs. modern split#

Perl carries two parallel argument-passing mechanisms:

# Classic: @_ aliasing, manual unpacking
sub add {
    my ($a, $b) = @_;
    return $a + $b;
}

# Modern: signatures, named lexicals, arity checking
use feature 'signatures';
sub add ($a, $b) {
    return $a + $b;
}

Both are fully supported. Signatures are not a replacement for @_; they are an additional, more declarative entry into the same calling convention. Inside a signature-using sub, @_ is still populated (this is implementation-defined and discouraged to rely on, but it is the case in 5.42).

The split between classic and modern is the single most useful piece of orientation when reading other people’s Perl. Most older code uses the classic form; most newer code uses signatures; both will be in front of you on any non-trivial codebase.

See also#