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;
}

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) { 
    ...
}

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) {
    ...
}

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.

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.

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;
}

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;

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.

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.