📘 Typed arguments in Perl 6 subs

Similarly to the above-described typed variables, it is possible to indicate that the sub’s parameters are typed. To do so, add a type name before the name of the parameter.

sub say-hi(Str $name) {
    say "Hi, $name!";

If the types of the expected and the actual parameters do not match, a compile-time error will occur.

say-hi("Mr. X"); # OK

# say-hi(123); # Error: Calling say-hi(Int) will never work
               # with declared signature (Str $name)

📘 Optional parameters in Perl 6 subs

Optional parameters are marked with a question mark after their names. The defined built-in function helps to tell if the parameter was really passed:

sub send-mail(Str $to, Str $bcc?) {
    if defined $bcc {
        # . . .
        say "Sent to $to with a bcc to $bcc.";
    else {
        # . . .
        say "Sent to $to.";

send-mail('mail@example.com', 'copy@example.com');

📘 Slurpy parameters and flattening in Perl 6

Perl 6 allows passing scalars, arrays, hashes, or objects of any other type as the arguments to a sub. There are no restrictions regarding the combination and its order in a sub declaration. For example, the first argument may be an array, and the second one may be a scalar. Perl 6 will pass the array as a whole. Thus the following scalar will not be eaten by the array.

In the following example, the @text variable is used inside the sub, and it contains only the values from the array passed in the sub call.

sub cute-output(@text, $before, $after) {
    say $before ~ $_ ~ $after for @text;

my @text = <C C++ Perl Go>;
cute-output(@text, '{', '}');

The output looks quite predictable.

The language expects that the sub receives the arguments of the same types that were listed in the sub declaration.

That also means, for example, that if the sub is declared with only one list argument, then it cannot accept a few scalars.

sub get-array(@a) {
    say @a;

get-array(1, 2, 3); # Error: Calling get-array(Int, Int, Int)
                    # will never work with declared signature (@a)

To let an array accept a list of separate scalar values, you need to say that explicitly by placing an asterisk before the argument name. Such an argument is called slurpy.

sub get-array(*@a) {
    say @a;

get-array(1, 2, 3); # Good: [1 2 3]

Similarly, it will work in the opposite direction, that is to say, when the sub expects to get a few scalars but receives an array when called.

sub get-scalars($a, $b, $c) {
    say "$a and $b and $c";

my @a = <3 4 5>;
get-scalars(@a); # Error: Calling get-scalars(Positional)
                 # will never work with declared
                 # signature ($a, $b, $c)

A vertical bar is used to unpack an array to a list of scalars.

get-scalars(|@a); # 3 and 4 and 5

📘 state variables in Perl 6

State variables (declared with the keyword state) appeared in Perl 5.10 and work in Perl 6. Such variables are initialized during the first call and keep their values in subsequent sub calls.

It is important to keep in mind that a single instance of the variable is created. Let us return to the example with a counter and replace the my declaration with the state one. The closure will now contain a reference to the same variable.

sub seq($init) {
     state $c = $init;
     return {$c++};

What happens when you create more than one closure?

my $a = seq(1);
my $b = seq(42);

All of them will reference the same variable, which will increase after calling either $a() or $b().

say $a(); # 1
say $a(); # 2
say $b(); # 3
say $a(); # 4
say $b(); # 5

📘 Function overloading in Perl 6

The multi keyword allows defining more than one function (or subroutine, or simply sub) with the same name. The only restriction is that those functions should have different signatures. In Perl 6, the signature of the sub is defined together with its name, and the arguments may be typed. In the case of multi subs, typed arguments make even more sense because they help to distinguish between different versions of the function with a single name and make a correct choice when the compiler needs to call one of them.

multi sub twice(Int $x) {
    return $x * 2;

multi sub twice(Str $s) {
    return "$s, $s";

say twice(42);   # 84
say twice("hi"); # hi, hi

As we have two functions here, one taking an integer argument and another expecting a string, the compiler can easily decide which one it should use.

📘 The need keyword to use a module in Perl 6

To just load a module and do no exports, use the need keyword.

Let us create a module named N, which contains the sub n(). This time, the sub is declared as our but with no is export.

unit module N; 

our sub n() {
    say "N::n()";

Then you need a module and may use its methods using the fully qualified names.

need N;

The sequence of the two instructions: need M; import M; (now import should always come after the need) is equivalent to a single use M; statement.

📘 Named arguments in Perl 6 subs

Apart from the positional parameters (those that have to go in the same order both in the sub definition and in the sub call), Perl 6 allows named variables, somewhat similar to how you pass a hash to a Perl 5 subroutine. To declare a named parameter, a colon is used:

sub power(:$base, :$exponent) {
    return $base ** $exponent;

Now, the name of the variable is the name of the parameter, and the order is not important anymore.

say power(:base(2), :exponent(3)); # 8
say power(:exponent(3), :base(2)); # 8

It is also possible to have different names for the named arguments and those variables, which will be used inside the sub. To give a different name, put it after a colon:

sub power(:val($base), :pow($exponent)) {
    return $base ** $exponent;

Now the sub expects new names of the arguments.

say power(:val(5), :pow(2)); # 25
say power(:pow(2), :val(5)); # 25

Alternatively, you can use the fatarrow syntax to pass named parameters as it is done in the following example:

say power(val => 5, pow => 2); # 25