The most basic form of a subroutine
is simply the sub
keyword, followed by the name of the
sub, followed by the block that defines the sub:
sub alert { print "We have normality."; }
In a simple sub, all arguments are passed in the
@_
array:
sub sum { my $sum; for @_ -> $number { $sum += $number; } return $sum; }
Perl 6 subroutines can define named formal parameters. The parameter list is part of the subroutine definition, often called the “signature” of the subroutine:
sub standardize ($text, $method) { my $clean; given $method { when 'length' { $clean = wrap($text, 72); } when 'lower' { $clean = lowercase($text); } ... } return $clean; }
Subroutine parameter lists are non-flattening. Any array or hash passed into a subroutine is treated as a single parameter. An array in the signature expects to be passed an actual array or arrayref, and a hash expects a hash or hashref:
sub whole (@names, %flags) { ... } # and elsewhere whole(@array, %hash);
To get the old-style behavior where the elements of an array (or the
pairs of a hash) flatten out into the parameter list, use the
flattening operator in the call to the subroutine. Here,
$first
is bound to @array[0]
and $second
is bound to
@array[1]
:
sub flat ($first, $second) { ... } flat(*@array);
To make an array (or hash) in the parameter list slurp up all the
arguments passed to it, use the flattening operator in the signature
definition. These are known as variadic parameters because they can
take a variable number of arguments. Here,
@names[0]
is bound to $zaphod
,
and @names[1]
to $ford
:
sub slurp (*@names) { ... } slurp($zaphod, $ford);
Subroutines with defined parameter lists don’t get
an @_
array. In fact, a simple subroutine without
a signature actually has an implicit signature of
*@_
:
sub simple { ... } # is the same as sub simple (*@_) { ... }
By default, parameters are passed by reference, but marked as
constant so they cannot be modified within the body of the
subroutine. The is
rw
property
marks a parameter as modifiable, so changes to the parameter within
the body of the sub modify the original variable passed in. The
is
copy
property marks a
parameter as passed by value, so the parameter is a lexically scoped
copy of the original value passed in:
sub passbyvalue ($first is copy, $second is copy) { ... } sub modifyparams ($first is rw, $second is rw) { ... }
Optional parameters are marked with a ?
before the
parameter name:
sub someopt ($required1, $required2, ?$optional1, ?$optional2) { ... }
A parameter can define the type of argument that will be passed to it. The type is defined before the argument name:
sub typedparams ( Int $first, Str $second) { ... }
The standard way of passing parameters is by position. The first argument passed in goes to the first parameter, the second to the second, and so on:
sub matchparams ($first, $second) { ... } matchparams($one, $two); # $one is bound to $first # $two is bound to $second
You can also pass parameters in by name, using a list of anonymous pairs. The key of each pair gives the parameter’s name and the value of the pair gives the value to be bound to the parameter. When passed by name, the arguments can come in any order. Optional parameters can be left out, even if they come in the middle of the parameter list. This is particularly useful for subroutines with a large number of optional parameters:
sub namedparams ($first, ?$second, ?$third is rw) { ... } namedparams(third => 'Trillian', first => $name);
You can specify that certain parameters will be passed only by name,
never by position, with a +
in place of the
?
to mark optional parameters:
sub namedparams ($first, +$second, +$third is rw) { ... }
You can define multiple routines with the same name but different
signatures. These are known as
"multimethods”
and defined with the multi
keyword instead of
sub
. They’re useful if you want a
routine that can handle different types of arguments in different
ways, but still appear as a single subroutine to the user. For
example, you might define an add
multimethod with
different behavior for integers, floats, and certain types of numeric
objects:
multi add (Int $first, Int $second) { ... } multi add (Num $first, Num $second) { ... } multi add (Imaginary $first, Imaginary $second) { ... } multi add (MyNum $first, MyNum $second) { ... }
When you later call the routine:
add($count, $total);
it will dispatch to the right version of add
based
on the types of the arguments passed to it.
Subroutines can be lexically scoped just like
variables. A my
-ed subroutine makes an entry in the
current lexical scratchpad with a &
sigil.
They’re called just like a normal subroutine:
if $dining { my sub dine ($who, $where) { ... } dine($zaphod, "Milliways"); } dine($arthur, "Nutri-Matic"); # error
The first call to the lexically scoped dine
is
fine, but the second is a compile-time error because
dine
doesn’t exist in the outer
scope.
Anonymous subroutines do everything that ordinary subroutines do. They can define a formal parameter list with optional and required parameters, take positional and named arguments, and do variadic slurping. The only difference is that they don’t define a name. They have to get the equivalent of a name somewhere, whether they’re assigned to a variable, passed as a parameter, aliased to another subroutine, or some other way. You can’t call a subroutine if you have no way to refer to it:
$make_tea = sub ($tealeaves, ?$sugar, ?$milk) { ... }
The arrow operator used with for
and
given
is just another way of defining anonymous
subroutines. The arrow doesn’t require parentheses
around its parameter list, but it can’t separate
required and optional parameters and can’t be used
to define named subs:
$make_tea = -> $tealeaves, $sugar, $milk { ... }
A bare block can also define an anonymous subroutine, but it can’t define a formal parameter list on the sub and can’t define a named sub.
$make_tea = { my $tea = boil 'tealeaves'; combine $tea, 'sugar', 'milk'; return $tea; }
Placeholder variables provide the
advantages of automatically named parameters, without the
inconvenience of defining a formal parameter list. You just use
variables with a caret after the
sigil—$^name
, @^name
, or
%^name
—within the
subroutine’s block, and the arguments passed into
the subroutine are bound to them. The order of the parameters is
determined by the Unicode sorting order of the
placeholder’s names, so the example below acts as if
it has a formal parameter list of ($^milk, $^sugar, $^tealeaves)
:
$make_tea = { my $tea = boil $^tealeaves; combine $tea, $^sugar, $^milk; return $tea; }
They’re handy in short subroutines and bare blocks, but get unwieldy quickly in anything more complicated:
@sorted = sort { $^a <=> $^b } @array;
Currying allows you
to create a shortcut for calling a
subroutine with some preset parameter
values. The assuming
method takes a list of named
arguments and returns a subroutine reference, with each of the named
arguments bound to the original subroutine’s
parameter list:
sub multiply ($multiplicand, $multiplier) { return $multiplicand * $multiplier; } $six_times = &multiply.assuming(multiplier => 6); $six_times(9); # 54 $six_times(7); # 42 ...
If you have a subroutine multiply
that multiplies
two numbers, you might create a subref $six_times
that sets the value for the $multiplier
parameter,
so you can reuse it several times.
Get Perl 6 Essentials now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.