Subroutines and Signatures

10.1 Classic Subroutines with @_

sub greet {
    my ($name, $greeting) = @_;           # arguments arrive in @_ (aliased to the caller's values)
    $greeting //= 'Hello';
    return "$greeting, $name!";
}
say greet('Ana');
say greet('Bo', 'Hi');

sub add_all {
    my $total = 0;
    $total += $_ for @_;
    return $total;                        # the last evaluated expression is returned implicitly anyway
}

sub get_shift {
    my $self = shift;                     # shift defaults to @_ inside a sub
    my %args = (size => 10, @_);          # named arguments via a hash with defaults
}

10.2 Signatures (Stable in 5.36)

use v5.36;     # enables signatures (and disables the old prototype-like syntax in sub declarations)

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

sub log_msg($level, $msg, @extra) {       # slurpy array
    say "[$level] $msg @extra";
}

sub configure(%opts) {                    # slurpy hash
    say "$_=$opts{$_}" for sort keys %opts;
}

sub ignore_second($first, $, $third) {    # unnamed placeholder parameter
    return $first + $third;
}

sub with_default_expr($x, $y = $x * 2) { $x + $y }   # defaults can use earlier params
sub maybe($x //= 10) { $x }               # //= and ||= defaults (5.38+): apply when undef/false is passed

greet('Ana');
# greet();   # dies: "Too few arguments for subroutine 'main::greet'"

10.3 Returning Values and Context

sub min_max(@nums) {
    my @sorted = sort { $a <=> $b } @nums;
    return ($sorted[0], $sorted[-1]);     # return a list
}
my ($min, $max) = min_max(3, 1, 9);

sub get_items { return wantarray ? @items : \@items }   # context-aware return

sub fail { return }                       # bare return: undef in scalar context, () in list context

10.4 Passing Arrays and Hashes

sub print_all($aref, $href) {             # pass references to avoid flattening
    say "Array: @$aref";
    say "Hash keys: @{[ sort keys %$href ]}";
}
print_all(\@fruits, \%age);

10.5 Prototypes, Recursion and Named Subs

sub factorial($n) { $n <= 1 ? 1 : $n * factorial($n - 1) }

use feature 'current_sub';                # __SUB__ for anonymous recursion (5.16+)
my $fact = sub ($n) { $n <= 1 ? 1 : $n * __SUB__->($n - 1) };

sub mygrep :prototype(&@) {               # prototypes affect parsing (block-taking subs), not argument checking
    my ($code, @list) = @_;
    return grep { $code->() } @list;
}
my @even = mygrep { $_ % 2 == 0 } 1..10;

&foo;     # old style: calls foo with the current @_ (avoid unless you mean it)
goto &foo;   # tail call: replaces the current sub (used in AUTOLOAD)