# Signatures A signature is a parenthesised parameter list that goes immediately after the sub name (and after any attributes), in place of — or in addition to — the body’s manual `@_` unpacking. Signatures introduce **lexical** parameter variables, perform **arity checking** at call time, and support default values and slurpy parameters. Signatures stabilised in Perl 5.36; in 5.42 they are a production feature available with one of: ```perl use feature 'signatures'; # explicit feature import use v5.36; # implicit (signatures + other 5.36 features) ``` PetaPerl supports the full 5.42 signature syntax. ## Basic shape ```perl use feature 'signatures'; sub add ($x, $y) { # two mandatory positional parameters return $x + $y; } add(2, 3); # 5 add(2); # error: Too few arguments add(2, 3, 4); # error: Too many arguments ``` Each `$name` in the signature declares a `my` lexical that receives the corresponding argument. Arity is checked at the call: the body never runs if the count is wrong. This is the most concrete improvement over the classic form: ```perl # Classic — silently accepts wrong arity sub add { my ($x, $y) = @_; return $x + $y; } add(2); # $y is undef; later arithmetic warns add(2, 3, 4); # third arg silently ignored ``` ## Defaults ```perl sub greet ($name, $greeting = 'Hello') { return "$greeting, $name!"; } greet('Alice'); # "Hello, Alice!" greet('Alice', 'Hi'); # "Hi, Alice!" ``` The default is an arbitrary expression evaluated each time the parameter is omitted (so `state` and per-call computation both work). It can reference earlier parameters: ```perl sub log_event ($message, $level = 'INFO', $prefix = "[$level]") { print "$prefix $message\n"; } log_event('starting'); # [INFO] starting log_event('failure', 'ERROR'); # [ERROR] failure log_event('done', 'OK', '>>'); # >> done ``` A default `= undef` is exactly equivalent to ”no default“ for arity (the parameter is still optional) but documents the intent. Use `//=`-style guards inside the body for ”`undef` means use my fallback“ semantics. ## Optional vs mandatory Parameters are mandatory by default. A parameter becomes optional by: - Giving it a default value (`$x = 42`). - Putting it after another optional parameter (transitive). - Being followed by a slurpy `@arr` or `%hash`. You cannot have a mandatory parameter after an optional one (except via slurpy): ```perl sub bad ($x = 1, $y) { ... } # error: Mandatory parameter follows optional ``` ## Slurpy parameters The last parameter may be a slurpy `@list` or `%hash`. It eats all remaining arguments: ```perl sub join_all ($sep, @parts) { return join $sep, @parts; } join_all(', ', 'a', 'b', 'c'); # "a, b, c" sub configure ($name, %opts) { $opts{verbose} //= 0; ... } configure('demo', verbose => 1, port => 8080); ``` The slurpy hash also fails if the remaining list has odd length: ```perl configure('demo', 'verbose'); # error: Odd-sized list given ``` This is the single most useful pattern signatures unlock: a named-parameter API with one positional plus a `%opts` slurp. ## Anonymous parameters A `$` (or `@`, `%`) with no name is a positional placeholder: ```perl sub second ($, $x) { return $x } second('ignored', 'kept'); # "kept" ``` This is mildly useful when adapting a callback to an interface that supplies more arguments than you care about. ## Combining defaults and slurpy ```perl sub render ($template, $cache = 1, %opt) { ... } render('greeting.tt'); # cache=1, %opt empty render('greeting.tt', 0); # cache=0, %opt empty render('greeting.tt', 1, locale => 'de'); # all three render('greeting.tt', locale => 'de'); # ERROR: 'locale' becomes $cache # then 'de' is the lone slurp arg # (odd-length hash) — diagnose carefully ``` That last case is the gotcha: a positional optional parameter followed by a slurpy hash is ambiguous with named-arg-only calls. Either drop the optional positional and put everything in the hash, or always pass the optional positional explicitly. ## Migration from `@_` unpacking The mechanical translation: ```perl # Before sub make_user { my ($name, $email, %extra) = @_; ... } # After use feature 'signatures'; sub make_user ($name, $email, %extra) { ... } ``` You get arity checking and named lexicals for free. The body is unchanged. The places where you cannot mechanically translate: - The body uses the *count* of arguments dynamically (`if (@_ >= 3)`) — signatures fix arity at parse time, so rework into an optional parameter with a default. - The body modifies `$_[0]` for the aliasing effect — keep the classic form, since signatures introduce *copies*, breaking the alias. - The body uses `goto &other` and wants to forward the original `@_` — `@_` is still populated under signatures in 5.42, but this is implementation-defined and may change. Keep the classic form for tail-call forwarding. ## Signatures and prototypes are orthogonal Signatures and [prototypes](prototypes.md) solve different problems: | Mechanism | Affects | When checked | Useful for | |-------------|-----------------------|----------------|---------------------| | signature | the body’s view | runtime | arity, named params | | prototype | how the parser parses | compile-time | DSL look-alikes | A sub can have both, with the prototype written as an attribute: ```perl use feature 'signatures'; sub mygrep :prototype(&@) ($code, @list) { grep { $code->($_) } @list; } mygrep { /foo/ } @items; # prototype lets us drop `sub` # signature gives us $code and @list ``` The prototype shapes the call site; the signature shapes the body. They do not duplicate each other. ## The single biggest reason to migrate Catching wrong-arity calls at the moment they happen — not several lines later when you finally do `$y + 1` and trip a warning about an undef value. Signatures turn a class of subtle bugs into a clear error message. ## See also - [Arguments and `@_`](arguments.md) — the classic mechanism that signatures coexist with. - [Prototypes](prototypes.md) — different mechanism, often confused with signatures. - [`sub`](../perlfunc/sub.md) — the keyword’s perlfunc page. - [Declaration](declaration.md) — where signatures sit in the declaration syntax. - [Scoping](scoping.md) — signature parameters are `my`-style lexicals.