Perl 5.36 Subroutine Signatures: Declarative Parameters Over Manual @_ Unpacking
Subroutine signatures in Perl 5.36 replace manual @_ unpacking with declarative parameter lists, explicit defaults, slurpy collection, and runtime arity checks.
25 Jul 2026, 08:41 UTC

The problem with classic @_ unpacking
In traditional Perl subroutines, the special array @_ holds all arguments passed at call time. A subroutine that expects two values typically begins with my ($level, $msg) = @_; while this works, the interface is undocumented at the definition site; readers must inspect the body to know what arguments are expected. Optional values require additional guards, and a call with too few or too many arguments does not fail; it silently supplies undef or leaves leftovers in @_ . This pattern also makes it easy to shift the wrong item when argument order changes, a common source of off‑by‑one bugs in larger codebases. The contract between caller and callee is implicit, lived only in documentation or habit.
Signatures become the declaration
Subroutine signatures, stabilized in Perl 5.36, invert this contract. A declaration such as sub log_msg ($level, $msg = q{}) { … } names each parameter in the signature itself. The named variables become lexical bindings inside the body; no manual @_ assignment is needed. The feature is enabled implicitly by use v5.36; or explicitly with use feature 'signatures';
Signatures support three practical patterns:
- Default values:
sub f ($x = 10)declares that$xdefaults to 10 when no argument is given. - Slurpy parameters:
sub f ($first, @rest)binds the first argument to$firstand collects any remaining arguments into the array@rest. - Arity enforcement: Calling a two‑parameter signature with one or three arguments raises a runtime error, catching misuse earlier than the classic silent acceptance.
Worked example: refactoring a logging helper
Consider a helper that prints a labeled message. The classic style typically starts with my ($level, $msg) = @_; and a guard $msg //= q{}.
On Perl 5.36+, the same function can be written with a signature:
sub log_msg ($level, $msg = q{}) {
# body
}
The signature makes the parameter names and defaults part of the interface, eliminating the my binding and the explicit undef guard. A call with the wrong number of arguments will raise a runtime error instead of silently producing undef.
Trade‑offs, version sensitivity, and practical verification
Signatures are not available on Perl versions earlier than 5.36 without the experimental feature pragma, and code that runs on mixed‑version fleets may emit warnings or fail to compile if signatures are used indiscriminately. From Perl 5.20 to 5.34, signatures required use feature 'signatures'; and emitted experimental warnings; they became non‑experimental only in 5.36.
Arity checks happen at call time, not compile time. They do not replace a test suite; they catch obvious misuse during development or deployment, but edge cases still need test coverage.
CPAN modules and legacy codebases overwhelmingly use @_ . Adopting signatures is a local team decision about readability and error detection, not a universal upgrade.
Verification on your system
- Run
perl -vin a terminal to confirm the interpreter version. No special permissions are required. Expect a version line starting withv5.36or later for stable signatures. - Create a test script with
use v5.36;and a signatured sub, e.g.:use v5.36; sub demo ($a, $b = 42) { print "$a $b\n" } demo(1) # demo(1, 2, 3) # would throw an error - Consult
perldoc perlsubon the target system for the signatures section to confirm the exact syntax and limitations for that Perl version.
Risks include deploying signatured code to a host running Perl earlier than 5.36, which will either emit experimental warnings or reject the syntax, and assuming signatures provide compile‑time safety when they only enforce arity at runtime.
Use signatures where you control the Perl version and want clearer contracts. Keep @_ where you need maximum portability or are interfacing with prototype‑heavy code. The shift from manual unpacking to declarative signatures is a small change that improves documentation, reduces boilerplate, and catches argument errors earlier without sacrificing Perl’s flexibility.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.