Subroutines and Signatures

14.1 Basics

sub greet($name) { "Hello, $name!" }       # the last expression is the return value
say greet('Ana');
sub add(Int $a, Int $b --> Int) { return $a + $b }   # typed parameters and return type
say add(2, 3);
# add('x', 3);                             # compile/run-time type error
my &doubler = sub ($x) { $x * 2 };          # anonymous sub
say doubler(21);
say &add.signature;                         # (Int $a, Int $b --> Int)
say &add.arity;                             # 2

14.2 Parameter Kinds

sub demo(
    $positional,                  # required positional
    $optional?,                   # optional positional (Any if not given)
    $with-default = 'def',        # optional with a default
    *@rest,                       # slurpy positional (flattening)
    :$named,                      # optional named
    :$required-named!,            # required named
    :name(:$n) = 'x',             # named with an alias: :name or :n
    Bool :$flag = False,          # boolean flag
    *%others,                     # slurpy named
) { }

sub log-msg($msg, :$level = 'INFO', :$timestamp = DateTime.now) { say "[$level] $msg" }
log-msg('started');
log-msg('oops', level => 'ERROR');
log-msg('debug', :level<DEBUG>);          # colon-pair syntax

sub sum(*@nums) { [+] @nums }             # slurpy (flattens arguments)
say sum(1, 2, 3, (4, 5));                 # 15
sub count-items(**@items) { @items.elems } # non-flattening slurpy
say count-items(1, (2, 3));               # 2
sub one-arg(+@items) { @items.elems }     # single-argument rule slurpy
say one-arg([1, 2, 3]), ' ', one-arg(1, 2); # 3 2

sub modify($x is copy) { $x *= 2; $x }   # local mutable copy
sub increment($x is rw) { $x++ } 
…

14.3 Constraints and Destructuring

sub positive(Int $n where * > 0) { $n }
sub between(Int $n where 1..10) { $n }
sub first-two([$first, $second, *@]) { "$first and $second" }   # destructure an array parameter
say first-two([10, 20, 30]);
sub point((:$x, :$y)) { "x=$x y=$y" }       # destructure named attributes/pairs
say point((:x(1), :y(2)).Hash);
sub swap(($a, $b)) { $b, $a }
say swap((1, 2));                          # (2 1)
sub typed-capture(Int:D $defined) { }      # :D = defined instances only (:U = type objects only)
# There's no `Int|Str $x` union syntax in signatures: use a subset (subset IntOrStr where Int|Str) or multis.

14.4 Captures

my $capture = \(1, 2, :named<x>);         # a Capture: positional + named arguments
sub show($a, $b, :$named) { "$a $b $named" }
say show(|$capture);                       # 1 2 x
say $capture.list, ' ', $capture.hash;
say \(1, 2) ~~ :($, $);                    # signature smartmatch: True

14.5 Return Values

sub min-max(@n) { @n.min, @n.max }        # return a list
my ($lo, $hi) = min-max([3, 1, 9]);
sub early($x) { return 'negative' if $x < 0; 'non-negative' }
sub nothing(--> Nil) { say 'side effect' }
sub returns-type(--> Str:D) { 'must be a defined Str' }
sub fact($n) { $n <= 1 ?? 1 !! $n * fact($n - 1) }
say fact(30);
sub fact-self($n) { $n <= 1 ?? 1 !! $n * &?ROUTINE($n - 1) }   # self-reference