Raku Programming/Subroutines
Subroutines
editWhen it comes to code reuse, the most basic building block is the subroutine. They are not the only building blocks in the toolkit however: Raku 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
editBlocks 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
editSubroutines 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
editOptional 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
editNormal 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
editRaku 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 Raku 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
editOnce 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
editIn 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!
Raku 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 Raku 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
editInstead 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