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)