Perl 6 Programming/Subroutines

From Wikibooks, open books for an open world
Jump to: navigation, search

Subroutines[edit]

When it comes to code reuse, the most basic building block is the subroutine. They are not the only building blocks in the toolkit however: Perl 6 also supports methods and submethods, that we'll discuss when we talk about classes and objects.

Subroutines are created with the sub keyword, followed by name, an optional list of parameters, and then a block of code.

Blocks[edit]

Blocks are groups of code contained in { } curly brackets. Blocks serve a number of purposes, including setting code apart, grouping several statements together, and creating a scope for variables.

Defining Subroutines[edit]

Subroutines are defined using the sub keyword. Here is an example:

sub mySubroutine () {
}

The parenthesis are used to define the list of formal parameters to the subroutine. Parameters are like regular my local variables, except they are initialized with values when the subroutine is called. Subroutines can pass a result back to their caller using the return keyword:

sub double ($x) {
    my $y = $x * 2;
    return $y;
}

Optional Parameters[edit]

Optional parameters have a ? after them. Also, optional parameters may be given a default value with =. Required parameters may have a ! after them, although this is the default for positional parameters. All required parameters must be listed before all optional ones.

sub foo (
    $first,       # First parameter, required
    $second!,     # Second parameter, required
    $third?,      # Third parameter, optional (defaults to undef)
    $fourth = 4   # Fourth parameter, optional (defaults to 4)
)

Named Parameters[edit]

Normal parameters are passed by their position: The first passed parameter goes into the first positional argument, the second goes into the second, and so on. However, there is also a way to pass parameters by name, and to do so in any order. Named parameters are basically pairs, where a string name is associated with a data value. Named data values can be passed using either pair or adverb syntax.

sub mySub(:name($value), :othername($othervalue))

Of course, subroutine signatures allow a special shorthand, that you can use if your variable has the same name as the pair has:

sub mySub(:name($name), :othername($othername))
 
sub mySub(:$name, :$othername)      # Same!

In a subroutine declaration, named parameters must come after all required and optional positional parameters. Named parameters are treated as optional by default unless they are followed by a !. Actually, you can put a ! after required positional parameters as well, but that's the default.

sub mySub(
    :$name!,             # Required
    :$type,              # Optional
    :$method?            # Still optional
)

Slurpy Parameters[edit]

Perl6 also allows so called "slurpy" parameters using the *@ syntax.

sub mySub($scalar, @array, *@theRest) {
  say "the first argument was: $scalar";
  say "the second argument was: " ~ @array;
  say "the rest were: " ~ @theRest;
}

The *@ tells perl 6 to flatten out the rest of the arguments into a list and store in the array @theRest. This is necessary to allow perl to accept positional or named arrays without requiring references.

  my $first = "scalar";
  my @array = 1, 2, 3;
  mySub($first, @array, "foo", "bar");

The above code will output three lines:

  • the first argument was :scalar
  • the second argument was 1, 2, 3
  • the rest were: "foo", "bar"

return and want[edit]

Calling Subroutines[edit]

Once we have a subroutine defined, we can call into it later to retrieve results or actions from it. We've already seen the built-in say function, where you can pass strings to it, and have those strings printed to the console. We can use our Double function from above to calculate various values:

my $x = double(2);       # 4
my $y = double(3);       # 6
my $z = double(3.5);     # 7

We can use the & sigil to store a reference to the subroutine into a normal scalar variable:

my $sub = &double;
my $x = $sub(7)          # 14

Multi Subroutines[edit]

In this example, you see that we are passing both integer values and floating point values to our Double subroutine. However, we can use our type specifiers to restrict what kinds of values

sub double (Int $x) {    # $x can only be an int!
   return $x * 2;
}
 
my $foo = double(4);     # 8
my $bar = double(1.5);   # Error!

Perl 6 allows you to write multiple functions with the same name, so long as they have different parameter signatures and are marked with the key word multi. This is called multi method dispatch, and is an important aspect of Perl 6 programming.

multi sub double(Int $x) {
    my $y = $x * 2;
    say "Doubling an Integer $x: $y";
    return $x * 2;
}
 
multi sub double(Num $x) {
    my $y = $x * 2;
    say "Doubling a Number $x: $y";
    return $x * 2;
}
 
my $foo = double(5);        # Doubling an Integer 5: 10
my $bar = double(3.5);      # Doubling a Number 3.5: 7

Anonymous Subroutines[edit]

Instead of naming a subroutine like normal, we can define an anonymous subroutine and store a reference to it in a variable.

my $double = sub ($x) { return $x * 2; };
my $triple = sub ($x) { return $x * 3; };
 
my $foo = $double(5);     # 10
my $bar = $triple(12);    # 36

Notice that we could also store these code references in an array:

my @times;
@times[2] = sub ($x) { return $x * 2; };
@times[3] = sub ($x) { return $x * 3; };
 
my $foo = @times[2](7);     # 14
my $bar = @times[3](5);     # 15