Use Perl 5.36 Subroutine Signatures for Cleaner Parameter Handling
Replace manual @_ shifting with stable subroutine signatures in Perl 5.36+, including defaults and slurpy parameters, with caveats for type validation.
07 Feb 2026, 14:12 UTC

Stop shifting @_ for every subroutine parameter
Perl programs often begin every subroutine with a list of shifts: my ($name, $count) = @_;. This works, but it hides the parameter list inside the function body, makes defaults awkward, and lets callers pass the wrong number of arguments without an immediate error.
The useful takeaway: if you are on Perl 5.36 or later, subroutine signatures are stable. You can declare parameters directly in the sub header, supply defaults, and collect extra arguments into a slurpy array or hash. Type constraints are not built in, so you still need a validation module for strict type checking.
Prerequisites
- Perl 5.36 or newer. Signatures existed experimentally in 5.20 through 5.34, but they emitted warnings and are not the stable target for new code.
- A shell or terminal where you can run
perl. - No special permissions are required to run or compile Perl scripts as your own user.
Check your Perl version
Run this in your terminal:
perl -v
Look for the line that says "This is perl 5, version 36" or higher. If you see 5.34 or older, signatures are experimental or unavailable depending on the exact release.
Enable stable signatures
At the top of your script, use:
use v5.36;
This enables strict, warnings, and the stable signatures feature together. If you cannot use v5.36, the older equivalent is:
use feature 'signatures';
no warnings 'experimental::signatures';
Only use the older form on Perl 5.20 through 5.34. On 5.36+, use v5.36; is sufficient and produces no experimental warnings.
Write your first signatured subroutine
Instead of shifting @_, list parameters in parentheses after the subroutine name:
use v5.36;
sub greet ($name) {
return "Hello, $name";
}
say greet("Ada");
Run it with perl script.pl. The parameter $name is a lexical copy of the first argument; you do not need to write my $name = shift;.
Defaults and optional parameters
Give a parameter a default value to make it optional:
sub repeat ($text, $times = 1) {
return $text x $times;
}
say repeat("ok"); # one argument
say repeat("ok", 3); # two arguments
If the caller omits $times, Perl assigns the default. You can place optional parameters only after required ones; a required parameter cannot follow an optional one in the signature.
Collect extra arguments with slurpy parameters
A slurpy parameter gathers remaining arguments into an array or hash. Prefix with @ for an array or % for a hash:
sub sum_all ($first, @rest) {
my $total = $first;
$total += $_ for @rest;
return $total;
}
say sum_all(10, 20, 30, 40);
For named-style arguments, use a hash slurpy:
sub configure (%options) {
say $options{timeout} // 30;
}
configure(timeout => 60, retries => 3);
The hash slurpy does not enforce keys or value types; it simply captures whatever key-value pairs the caller passes.
Understand what happens to @_
The @_ array still exists, but signature parameters are lexical copies. Modifying @_ inside the subroutine does not change the signature variables, and changing a signature variable does not alter @_. If you need the original argument list for introspection, @_ is still available, but mixing the two styles in one subroutine is usually confusing.
Add type constraints when you need them
Signatures do not validate types. Declaring ($count) does not stop a caller from passing a string. For type constraints, use a module such as Type::Params or MooseX::Method::Signatures:
use v5.36;
use Type::Params qw(compile);
use Types::Standard qw(Int Str);
sub set_limit ($limit) {
my $check = compile(Int);
my ($validated) = $check->(@_);
...
}
Install Type::Params from CPAN if it is not already available. Without it, signatures only handle argument counting and defaults, not type safety.
Verify the result
- Compile the script without executing it:
Expected: no syntax errors.perl -c script.pl - Run with warnings enabled:
Expected: noperl -w script.plexperimental::signatureswarnings on Perl 5.36+. - Run a small call:
Expected: the program prints 3. If you omituse v5.36; sub test ($a, $b = 1) { return $a + $b; } say test(2);$b, the default 1 applies.
If compilation fails with a syntax error near the signature, your Perl version is too old or use v5.36; is missing.
Limitations and recovery
- No native named parameters. Use a hash slurpy (
%options) or a dedicated module if you want named arguments. - No built-in type constraints. Pair signatures with
Type::Paramsor similar for validation. - You cannot combine a subroutine signature with a
prototypeattribute. Signatures replace prototypes. - Code using signatures will not compile on Perl 5.18 or earlier.
Because enabling signatures is a source-code change, there is no system state to roll back. If you need to support an older Perl, remove use v5.36;, rewrite the affected subroutines to use my ($x) = @_;, and redeploy the script. Test with perl -c after the rewrite.
Quick reference
| Pattern | Signature | Meaning |
|---|---|---|
| Required scalar | sub f ($x) | Exactly one argument expected at that position |
| Optional scalar | sub f ($x = 7) | Uses 7 when omitted |
| Slurpy array | sub f ($x, @rest) | Captures remaining positional arguments |
| Slurpy hash | sub f (%opts) | Captures key-value pairs |
| Enable feature | use v5.36; | Stable signatures on Perl 5.36+ |
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.