Usually known as function in other languages, a subroutine (or sub for short) helps to organize and structure code. There's not distinction between a sub that returns a value and one that doesn't; they're both considered subroutines.
sub shout-hello {
say "Helloooo!";
}
shout-hello; # calling the sub
shout-hello(); # same as above
sub greet {
return 'Greeting from here!";
}
greet(); # returned value in `sink` context so it's lost
say greet(); # returned value being used
# The last expression of sub is returned implicitly.
# Thus the keyword `return` can be omitted which helps
# to simplify subs with a single expression. The semicolon
# can as well be omitted in the last expression.
sub farewell {
say "See you 'till later!"
}
farewell();
$ perl6 sub-declaration.p6
Helloooo!
Helloooo!
Greeting from here!
See you 'till later!
Positional parameters are defined by their position. They're are required by
default but can be specified as optional by using a default value or appending
a ?
to their names.
Named parameters are defined by their names. They're created by prepending a
:
to their names. Although optional by default, they can be made required
by appending a !
to their names.
# 2nd parameter with default value. Required
# parameter must come first.
sub pos-fullname( $fname, $lname = "Doe" ) {
return "$fname $lname"
}
say pos-fullname("Joe");
say pos-fullname("Tabia", "Lock");
# 1st parameter with default value
sub named-fullname( :$firstname = "Joe", :$lastname ) {
return "$firstname $lastname"
}
say named-fullname( lastname => "Dreia" );
say named-fullname( firstname => "Cedra", lastname => "Etian" );
# Mixing positional and named parameters.
# Positional must always come first.
sub t-fullname( $title, :$firstname, :$lastname) {
return $title ~ ". $firstname $lastname"
}
say t-fullname("Mr", firstname => "Sachio", lastname => "Eldos");
$ perl6 parameters.p6
Joe Doe
Tabia Lock
Joe Dreia
Cedra Etian
Mr. Sachio Eldos
The list of parameters of a subroutine can be typed and further constraint
can be specified by the definedness of the passed values. To accept only defined
values of a certain type, append :D
to the type. On the other hand, to accept
only undefined values, append :U
.
sub display-value( Str $v ) {
say $v;
}
display-value('Hello');
display-value(Str);
#display-value(5); # Error
sub display-defined-value( Str:D $v ) {
say $v;
}
display-defined-value('Hello');
#display-defined-value(Str); # Error
sub display-undefined-value( Str:U $v ) {
say $v;
}
display-undefined-value(Str);
#display-undefined-value('Hello'); # Error
$ perl6 typed-parameters.p6
Hello
(Str)
Hello
(Str)
The return type of a subroutine can be specified by using -->
followed by either the type or literal value right after the parameters list.
sub multiply( $f1, $f2 --> Int ) {
$f1 * $f2
}
say multiply(5, 3);
#say multiply(2,5, 3); # Error
# Both typed parameters and typed return
sub sum( Int $s1, Int $s2 --> Int ) {
$s1 + $s2
}
say sum(23, 6);
#say sum(15.2, 1.7); # Error
$ perl6 typed-returns.p6
15
29
A signature refers to the number and type of parameters defined by a routine. On the hand, a capture refers to the list of arguments a signature accepts. Thus, when a routine is defined we talk about its signature and when it's called, then we talk about its capture.
sub display( Str $person, Int $age ) {
#^^^^^^^^^^^^^^^^^^^^^^^^^ <- the sub's signature
say "Person: $person, Age: $age";
}
display("Andrew Heid", 50);
#^^^^^^^^^^^^^^^^^^^ <- the sub's capture
Literal signatures are created by prepending a :
to a list of parameters and
literal captures by prefixing a list of terms with \
.
my $sig = :(Str $person, Int $age);
say ('Laurent Nga', 25) ~~ $sig; # smartmatching against the signature
my $cap = \('Laura Sua', 27);
say $cap ~~ $sig; # smartmatching the capture against
# the signature
# To use a capture in a subroutine call, prepend it with a `|`. This would
# be like passing the values directly to the sub.
display(|$cap);
$ perl6 sig-cap.p6
Person: Andrew Heid, Age: 50
True
True
Person: Laura Sua, Age: 27
An anonymous subroutine is a sub without a name. It's created by storing a
sub
with its parameter list and body in a variable.
my $add = sub ( $x , $y) { $x + $y };
say "3 + 7 = ", $add(3, 7);
$ perl6 anon-sub01.p6
3 + 7 = 10
A regular sub can be stored in a variable. As result, the sub can be called
by its name and its handle(s). To forbid calling the sub by its name,
use the anon
keyword.
my $m1 = sub multiply ($a, $b) { $a * $b }
my $m2 = $m1;
say "1 x -9 = ", multiply(-1, -9);
say "2 x 7 = ", $m1(2, 7);
say "(i)(2+i) = ", $m2(i, 2+i);
# A regular sub can be stored in a variable by
# appending a `&` to the sub's name.
sub subtract($a, $b) { $a - $b }
my $s1 = &subtract;
say "1 - 5 = ", subtract(1,5);
say "5 - 2 = ", $s1(5,2);
# Using `anon`:
my $greet = anon sub greet(Str $name) { say "Hello, $name!" }
$greet("Jules");
#greet("Erl"); # Error: Undeclared subroutine
$ perl6 anon-sub02.p6
1 x -9 = 9
2 x 7 = 14
(i)(2+i) = -1+2i
1 - 5 = -4
5 - 2 = 3
Hello, Jules!
Instead of anonymous subs, you can utilize anonymous block of codes called
pointy blocks. They are declared with an arrow ->
and their parameters lists
must be listed without parentheses.
my $name-n-times = -> Str $name, Int $times { say $name for 1..$times }
$name-n-times('Al', 5);
# The arrow can be dropped and instead use placeholder parameters
# with the `^$` twigil.
my $print-it = { say "$^a: $^b" }
# Equivalent to `my $print-it = -> $a, $b { say "$a: $b" }`
$print-it("Number", 15);
my $print-it-reverse = { say "$^b: $^a" }
# Equivalent to `my $print-it = -> $a, $b { say "$b: $a" }`
$print-it-reverse("Number", 15);
$ perl6 anon-sub03.p6
Al
Al
Al
Al
Al
Number: 15
15: Number
For more info, go to: