NAME
Perl6::Overview::Subroutine - Subroutines
DESCRIPTION
Positional parameters
sub foo ($bar, @baz, %grtz) {...}
# Global (our()) subroutine &foo, taking a scalar, an array,
# and a hash.
foo(42, @array, %hash); # works
foo(bar => 42, baz => @array, grtz => %hash); # works as well
foo(:bar(42), :baz(@array), :grtz(%hash)); # ditto
# Mixing named and positional arguments is allowed, too:
foo(42, :baz(@array), :grtz(%hash)); # works
Positional parameters are required by default.
Named parameters
sub foo (:$named_only) {...}
foo 42; # illegal
foo named_only => 42; # ok
foo :named_only(42); # ok
Named parameters are optional be default.
Optional parameters
sub foo ($bar?) {...}
sub foo ($bar is optional) {...}
foo(); # ok
foo(42); # ok
sub foo (:$bar?) {...} # allowed, but could be written as
sub foo (:$bar) {...} # as named parameters are optional by
# default.
You can specify defaults:
sub foo ($bar = 42) {...}
foo(); # $bar is 42
foo(17); # $bar is 17
sub foo (:$bar = 42) {...}
foo(); # $bar is 42
foo(:bar(17)); # $bar is 17
Defaults are calculated at runtime and can even refer to preceding parameters:
sub foo ($bar, $baz = grmbl($bar)) {...}
Required parameters
sub foo (:$bar!) {...} # Required named parameter $bar
sub foo (:$bar is required) {...} # same
sub foo ($bar!) {...} # allowed, but could be written as
sub foo ($bar) {...} # as positional parameters are required
# by default.
Slurpy parameters
Slurpy arrays slurp all remaining positional arguments:
sub foo ($a, $b, *@rest) {...}
foo 1,2,3,4,5; # $a is 1, $b is 2, @rest is (3,4,5)
foo 1,2; # $a is 1, $b is 2, @rest is ()
Slurpy hashes slurp all remaining named arguments:
sub foo ($a, $b, *%rest) {...}
foo 1,2,3,4,5; # error: "Too many positional arguments"
foo 1,2, :foo<bar>; # $a is 1, $b is 2, %rest is (foo => "bar")
"is rw"
By default, all parameters are read-only aliases:
sub foo ($var) { $var = 42 };
my $bar = 17; foo($bar); # dies: "Cannot modify read-only variable"
"is rw" causes *no* read-only proxy to be created:
sub foo ($var is rw) { $var = 42 };
my $bar = 17; foo($bar); # works, $bar is 42 after the function call
"is copy"
"is copy" copies the variable, the original will remain unaffected:
sub foo ($var is copy) { $var = 42 };
my $bar = 17; foo($bar); # works, but $bar unchanged
(This is the same as Perl 5's "my $var = shift" idiom.)
Note that "is rw" and "is copy" only refer to the first level of a structure:
sub foo (@array) { @array[42] = 17 }
foo @some_array; # works, even though @array is not "is rw";
# @some_array[42] changed to 17
sub foo (@array) { push @array, 17 }
foo @some_array; # does not work ("Cannot modify read-only
# variable")
sub foo (@array is rw) { push @array, 17 }
foo @some_array; # does work, 17 appended to @some_array
Similarly, "is rw" and "is copy" may not do what you think they do on references:
sub foo (Ref $ref) { $$ref = 17 }
foo $some_ref; # works, $$some_ref changed to 17
sub foo (Ref $ref) { $ref = \$other_var }
foo $some_ref; # dies ("Cannot modify read-only variable"
sub foo (Ref $ref is rw) { $ref = \$other_var }
foo $some_ref; # works, $some_ref changed to \$other_var
Re-binding parameters
The following code is legal and does not die:
sub foo ($var) { $var := $some_other_var; ... }
foo 42;
foo $some_var;
But the original containers are not modified in any way, neither 42 nor $some_var get rebound, only &foo's $var does no longer refer to 42 or $some_var, but to $some_other_var.
[XXX: Unpacking arrays and hashes, pattern matching, specifying parameter types]
Specifying the scope of a declaration
sub foo {...}
# our() subroutine, may be called before the declaration:
foo(...); sub foo {...} # legal
# (Note that this is sugar for
# BEGIN { our &foo := sub (...) {...} })
my sub foo {...}
# Lexical (my()) subroutine, may not be called before the declaration.
# Only visible in the scope in which it was declared:
{ my sub foo {...}; foo(...) } # legal
{ foo() } # illegal
# ("Can't find subroutine &foo")
our sub foo {...}
# our() subroutine, may not be called before the declaration.
sub *foo {...}
# Really global subroutine, visible in all scopes.
"is rw" on a subroutine
"is rw" applied to a subroutine causes *no* read-only proxy to be
created around the return value of a subroutine:
sub foo { $some_var }
foo() = 42; # error: "Cannot modify read-only variable"
sub foo is rw { $some_var }
foo() = 42; # works, $some_var set to 42
sub foo is rw { 17 }
foo() = 42; # still does not work -- 17 is a constant
# Instead use:
sub foo is rw { my $var = 17 }
foo() = 42; # works
The "Proxy" class
Following the "assignments should look like assignments" rule, usage of "is rw" for accessor-like subroutines is encouraged. You can use the "Proxy" class to validate input:
sub foo () is rw {
return new Proxy:
FETCH => { ...code to return on get... },
STORE => -> $new { ...code to run on assignment... };
}
say foo();
foo() = 42;
Note that assigning a proxy to a variable with = will loose the proxy's magicalness:
my $var = foo(); # invokes FETCH on foo()
$var = $invalid_input; # works; STORE not called
You have to use binding (:=) instead:
my $var := foo();
$var = $invalid_input; # STORE called
Calling subroutines
Whitespace matters:
foo 42; # calls &foo, one positional argument (number 42)
foo(42); # same, the parens are sub call parens (postfix .())
foo (42); # same, but the parens are grouping parens
foo 42, 23; # two positional arguments (42 and 23)
foo(42, 23); # same
foo (42, 23); # one positional argument (the array (42, 23))
Parentheses matter:
foo bar => 42; # one named argument (42)
foo :bar(42); # same
foo(bar => 42); # same, the parens are grouping parens
foo(:bar(42)); # same, the parens are grouping parens
foo (bar => 42); # one positional argument (the pair (bar => 42))
foo (:bar(42)); # same, the parens mark the pair to be a Pair object,
# not a named argument
Splatting:
foo $pair; # one positional argument ($pair)
foo [,] $pair; # one named argument
# ($pair.value passed by the name $pair.key)
foo @array; # one positional argument (the array @array)
foo [,] @array; # many positional arguments
# (@array's contents are passed positionally)
foo %hash; # one positional argument (the hash %hash)
foo [,] %hash; # many named arguments
# (%hash.values are passed by the names %hash.keys)