4.4 Subroutines
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;
}
4.4.1 Formal Parameters
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) {
...
}
4.4.1.1 Named parameter passing
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) {
...
}
4.4.2 Multimethods
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.
4.4.3 Lexical Scope
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.
4.4.4 Anonymous Subroutines
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;
}
4.4.5 Placeholder Variables
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;
4.4.6 Currying
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.
|