Synopsis 6: Subroutines
Damian Conway <damian@conway.org> and Allison Randal <al@shadowed.net>
Maintainer: Larry Wall <larry@wall.org> Date: 21 Mar 2003 Last Modified: 17 Mar 2008 Number: 6 Version: 94
This document summarizes Apocalypse 6, which covers subroutines and the new type system.
From t/blocks/sub_return_values.t lines 8–228 (63 √, 0 ×): (skip)
| L<S06/"Subroutines and other code objects"> |
| |
| See also t/blocks/return.t, which overlaps in scope. |
| |
| =cut |
| |
| # NOTE: the smart link above actually doesn't go to a good |
| # reference for the spec for 'return', but I couldn't find |
| # one either. |
| |
| plan 63; |
| |
| # These test the returning of values from a subroutine. |
| # We test each data-type with 4 different styles of return. |
| # |
| # The datatypes are: |
| # Scalar |
| # Array |
| # Array-ref (aka List) |
| # Hash |
| # Hash-ref |
| # |
| # The 4 return styles are: |
| # create a variable, and return it with the return statement |
| # create a variable, and make it the last value in the sub (implied return) |
| # create the value inline and return it with the return statement |
| # create the value inline and make it the last value in the sub (implied return) |
| # |
| # NOTE: |
| # we do not really check return context here. That should be |
| # in it's own test file |
| |
| # TODO-NOTE: |
| # Currently the Hash and Hash-ref tests are not complete, becuase hashes seem to be |
| # broken in a number of ways. I will get back to those later. |
| |
| ## void |
| # ok(eval('sub ret { return }; 1'), "return without value parses ok"); |
| |
| sub bare_return { return }; |
| |
√ | ok(! bare_return(), "A bare return is a false value"); |
| |
| my @l = <some values>; |
| @l = bare_return(); |
√ | is( @l, [], "A bare return is an empty list in array/list context"); |
| |
| my $s = "hello"; |
| $s = bare_return(); |
√ | is($s, undef, "A bare return is undef in scalar context"); |
| |
| ## scalars |
| |
| sub foo_scalar { |
| my $foo = 'foo'; |
| return $foo; |
| } |
√ | is(foo_scalar(), 'foo', 'got the right return value'); |
| |
| # ... w/out return statement |
| |
| sub foo_scalar2 { |
| my $foo = 'foo'; |
| $foo; |
| } |
√ | is(foo_scalar2(), 'foo', 'got the right return value'); |
| |
| # ... returning constant |
| |
| sub foo_scalar3 { |
| return 'foo'; |
| } |
√ | is(foo_scalar3(), 'foo', 'got the right return value'); |
| |
| # ... returning constant w/out return statement |
| |
| sub foo_scalar4 { |
| 'foo'; |
| } |
√ | is(foo_scalar4(), 'foo', 'got the right return value'); |
| |
| ## arrays |
| |
| sub foo_array { |
| my @foo = ('foo', 'bar', 'baz'); |
| return @foo; |
| } |
| my @foo_array_return = foo_array(); |
√ | isa_ok(@foo_array_return, 'Array'); |
√ | is(+@foo_array_return, 3, 'got the right number of return value'); |
√ | is(@foo_array_return[0], 'foo', 'got the right return value'); |
√ | is(@foo_array_return[1], 'bar', 'got the right return value'); |
√ | is(@foo_array_return[2], 'baz', 'got the right return value'); |
| |
| # ... without the last return statement |
| |
| sub foo_array2 { |
| my @foo = ('foo', 'bar', 'baz'); |
| @foo; |
| } |
| my @foo_array_return2 = foo_array2(); |
√ | isa_ok(@foo_array_return2, 'Array'); |
√ | is(+@foo_array_return2, 3, 'got the right number of return value'); |
√ | is(@foo_array_return2[0], 'foo', 'got the right return value'); |
√ | is(@foo_array_return2[1], 'bar', 'got the right return value'); |
√ | is(@foo_array_return2[2], 'baz', 'got the right return value'); |
| |
| # ... returning an Array constructed "on the fly" |
| |
| sub foo_array3 { |
| return ('foo', 'bar', 'baz'); |
| } |
| my @foo_array_return3 = foo_array3(); |
√ | isa_ok(@foo_array_return3, 'Array'); |
√ | is(+@foo_array_return3, 3, 'got the right number of return value'); |
√ | is(@foo_array_return3[0], 'foo', 'got the right return value'); |
√ | is(@foo_array_return3[1], 'bar', 'got the right return value'); |
√ | is(@foo_array_return3[2], 'baz', 'got the right return value'); |
| |
| # ... returning an Array constructed "on the fly" w/out return statement |
| |
| sub foo_array4 { |
| ('foo', 'bar', 'baz'); |
| } |
| my @foo_array_return4 = foo_array4(); |
√ | isa_ok(@foo_array_return4, 'Array'); |
√ | is(+@foo_array_return4, 3, 'got the right number of return value'); |
√ | is(@foo_array_return4[0], 'foo', 'got the right return value'); |
√ | is(@foo_array_return4[1], 'bar', 'got the right return value'); |
√ | is(@foo_array_return4[2], 'baz', 'got the right return value'); |
| |
| ## Array Refs aka - Lists |
| |
| sub foo_array_ref { |
| my $foo = ['foo', 'bar', 'baz']; |
| return $foo; |
| } |
| my $foo_array_ref_return = foo_array_ref(); |
√ | isa_ok($foo_array_ref_return, 'List'); |
√ | is(+$foo_array_ref_return, 3, 'got the right number of return value'); |
√ | is($foo_array_ref_return[0], 'foo', 'got the right return value'); |
√ | is($foo_array_ref_return[1], 'bar', 'got the right return value'); |
√ | is($foo_array_ref_return[2], 'baz', 'got the right return value'); |
| |
| # ... w/out the return statement |
| |
| sub foo_array_ref2 { |
| my $foo = ['foo', 'bar', 'baz']; |
| $foo; |
| } |
| my $foo_array_ref_return2 = foo_array_ref2(); |
√ | isa_ok($foo_array_ref_return2, 'List'); |
√ | is(+$foo_array_ref_return2, 3, 'got the right number of return value'); |
√ | is($foo_array_ref_return2[0], 'foo', 'got the right return value'); |
√ | is($foo_array_ref_return2[1], 'bar', 'got the right return value'); |
√ | is($foo_array_ref_return2[2], 'baz', 'got the right return value'); |
| |
| # ... returning list constructed "on the fly" |
| |
| sub foo_array_ref3 { |
| return ['foo', 'bar', 'baz']; |
| } |
| my $foo_array_ref_return3 = foo_array_ref3(); |
√ | isa_ok($foo_array_ref_return3, 'List'); |
√ | is(+$foo_array_ref_return3, 3, 'got the right number of return value'); |
√ | is($foo_array_ref_return3[0], 'foo', 'got the right return value'); |
√ | is($foo_array_ref_return3[1], 'bar', 'got the right return value'); |
√ | is($foo_array_ref_return3[2], 'baz', 'got the right return value'); |
| |
| # ... returning list constructed "on the fly" w/out return statement |
| |
| sub foo_array_ref4 { |
| ['foo', 'bar', 'baz']; |
| } |
| my $foo_array_ref_return4 = foo_array_ref4(); |
√ | isa_ok($foo_array_ref_return4, 'List'); |
√ | is(+$foo_array_ref_return4, 3, 'got the right number of return value'); |
√ | is($foo_array_ref_return4[0], 'foo', 'got the right return value'); |
√ | is($foo_array_ref_return4[1], 'bar', 'got the right return value'); |
√ | is($foo_array_ref_return4[2], 'baz', 'got the right return value'); |
| |
| ## hashes |
| |
| sub foo_hash { |
| my %foo = ('foo', 1, 'bar', 2, 'baz', 3); |
| return %foo; |
| } |
| |
| my %foo_hash_return = foo_hash(); |
√ | isa_ok(%foo_hash_return, 'Hash'); |
√ | is(+%foo_hash_return.keys, 3, 'got the right number of return value'); |
√ | is(%foo_hash_return<foo>, 1, 'got the right return value'); |
√ | is(%foo_hash_return<bar>, 2, 'got the right return value'); |
√ | is(%foo_hash_return<baz>, 3, 'got the right return value'); |
| |
| my $keys; |
√ | lives_ok({ $keys = +(foo_hash().keys) }, |
| "can call method on return value (hashref)"); |
√ | is($keys, 3, "got right result"); |
√ | lives_ok({ foo_hash()<foo> }, |
| "can hash de-ref return value (hashref)"); |
| |
| # now hash refs |
| |
| sub foo_hash_ref { |
| my %foo = ( 'foo', 1, 'bar', 2, 'baz', 3 ); |
| return \%foo; |
| } |
| |
| my $foo_hash_ref_return = foo_hash_ref(); |
√ | isa_ok($foo_hash_ref_return, 'Hash'); |
√ | is(+$foo_hash_ref_return.keys, 3, 'got the right number of return value'); |
√ | is($foo_hash_ref_return<foo>, 1, 'got the right return value'); |
√ | is($foo_hash_ref_return<bar>, 2, 'got the right return value'); |
√ | is($foo_hash_ref_return<baz>, 3, 'got the right return value'); |
| |
√ | lives_ok({ $keys = +(foo_hash_ref().keys) }, |
| "can call method on return value (hashref)"); |
√ | is($keys, 3, "got right result"); |
√ | lives_ok({ foo_hash_ref()<foo> }, |
| "can hash de-ref return value (hashref)"); |
Subroutines (keyword: sub) are non-inheritable routines with parameter lists.
Methods (keyword: method) are inheritable routines which always have an associated object (known as their invocant) and belong to a particular kind or class.
Submethods (keyword: submethod) are non-inheritable methods, or subroutines masquerading as methods. They have an invocant and belong to a particular kind or class.
Regexes (keyword: regex) are methods (of a grammar) that perform pattern matching. Their associated block has a special syntax (see Synopsis 5). (We also use the term "regex" for anonymous patterns of the traditional form.)
Tokens (keyword: token) are regexes that perform low-level non-backtracking (by default) pattern matching.
Rules (keyword: rule) are regexes that perform non-backtracking (by default) pattern matching (and also enable rules to do whitespace dwimmery).
Macros (keyword: macro) are routines whose calls execute as soon as they are parsed (i.e. at compile-time). Macros may return another source code string or a parse-tree.
From t/blocks/multi_sub.t lines 51–69 (3 √, 2 ×): (skip)
| # L<S06/"Routine modifiers"> |
| |
| multi declared_wo_sub (Int $x) { 1 } |
| multi declared_wo_sub (Str $x) { 2 } |
√ | is declared_wo_sub(42), 1, "omitting 'sub' when declaring 'multi sub's works (1)"; |
× | is declared_wo_sub("42"), 2, "omitting 'sub' when declaring 'multi sub's works (2)"; |
| |
| # Test for slurpy MMDs |
| |
| proto mmd {} # L<S06/"Routine modifiers"> |
| multi mmd () { 1 } |
| multi mmd (*$x, *@xs) { 2 } |
| |
× | is(mmd(), 1, 'Slurpy MMD to nullary'); |
√ | is(mmd(1,2,3), 2, 'Slurpy MMD to listop via args'); |
√ | is(mmd(1..3), 2, 'Slurpy MMD to listop via list'); |
| |
| # Test for proto definitions |
| |
Multis (keyword: multi) are routines that can have multiple variants that share the same name, selected by arity, types, or some other constraints.
Prototypes (keyword: proto) specify the commonalities (such as parameter names, fixity, and associativity) shared by all multis of that name in the scope of the proto declaration. A proto also adds an implicit multi to all routines of the same short name within its scope, unless they have an explicit modifier. (This is particularly useful when adding to rule sets or when attempting to compose conflicting methods from roles.)
From t/blocks/proto.t lines 7–23 (no results): (skip)
| #L<S06/"Routine modifiers"/Prototypes> |
| { |
| |
| eval q[ proto sub f1 {...} ]; |
| eval q[ proto method f2 {...} ]; |
| eval q[ proto macro f3 {...} ]; |
| eval q[ proto regex f4 {...} ]; |
| eval q[ proto token f5 {...} ]; |
| eval q[ proto rule f6 {...} ]; |
| |
| ok( eval('&f1'), 'proto modifier to sub' ); |
| ok( eval('&f2'), 'proto modifier to method' ); |
| ok( eval('&f3'), 'proto modifier to macro' ); |
| ok( eval('&f4'), 'proto modifier to regex', :todo<bug> ); |
| ok( eval('&f5'), 'proto modifier to token', :todo<bug> ); |
| ok( eval('&f6'), 'proto modifier to rule', :todo<bug> ); |
| } |
Only (keyword: only) routines do not share their short names with other routines. This is the default modifier for all routines, unless a proto of the same name was already in scope.
A modifier keyword may occur before the routine keyword in a named routine:
only sub foo {...}
proto sub foo {...}
multi sub foo {...}
only method bar {...}
proto method bar {...}
multi method bar {...}
If the routine keyword is omitted, it defaults to sub.
Modifier keywords cannot apply to anonymous routines.
From t/blocks/scoped_named_subs.t lines 5–35 (8 √, 0 ×): (skip)
| # L<S06/Named subroutines> |
| |
| #first lets test lexical named subs |
| { |
| my String sub myNamedStr() { return 'string' }; |
√ | is myNamedStr(), 'string', 'lexical named sub() return String'; |
| } |
√ | is eval('myNamedStr()'), '', 'Correct : lexical named sub myNamedStr() should NOT BE available outside its scope'; |
| |
| { |
| my Int sub myNamedInt() { return 55 }; |
√ | is myNamedInt(), 55, 'lexical named sub() return Int'; |
| } |
√ | is eval('myNamedInt()'), '', 'Correct : lexical named sub myNamedInt() should NOT BE available outside its scope'; |
| |
| |
| #packge-scoped named subs |
| |
| { |
| our String sub ourNamedStr() { return 'string' }; |
√ | is ourNamedStr(), 'string', 'package-scoped named sub() return String'; |
| } |
√ | is ourNamedStr(), 'string', 'Correct : package-scoped named sub ourNamedStr() should BE available in the whole package'; |
| |
| |
| { |
| our Int sub ourNamedInt() { return 55 }; |
√ | is ourNamedInt(), 55, 'package-scoped named sub() return Int'; |
| } |
√ | is ourNamedInt(), 55, 'Correct : package-scoped named sub ourNamedInt() should BE available in the whole package'; |
| |
The general syntax for named subroutines is any of:
my RETTYPE sub NAME ( PARAMS ) TRAITS {...} # lexical only
our RETTYPE sub NAME ( PARAMS ) TRAITS {...} # also package-scoped
sub NAME ( PARAMS ) TRAITS {...} # same as "our"
The return type may also be put inside the parentheses:
sub NAME (PARAMS --> RETTYPE) {...}
Unlike in Perl 5, named subroutines are considered expressions, so this is valid Perl 6:
my @subs = (sub foo { ... }, sub bar { ... });
From t/data_types/anon_block.t lines 19–28 (4 √, 0 ×): (skip)
| # L<S06/"Anonymous subroutines"> |
| # anon blocks |
| my $anon_sub = sub { 1 }; |
√ | isa_ok($anon_sub, 'Sub'); |
√ | is($anon_sub(), 1, 'sub { } works'); |
| |
| my $anon_sub_w_arg = sub ($arg) { 1 + $arg }; |
√ | isa_ok($anon_sub_w_arg, 'Sub'); |
√ | is($anon_sub_w_arg(3), 4, 'sub ($arg) {} works'); |
| |
The general syntax for anonymous subroutines is:
sub ( PARAMS ) TRAITS {...}
But one can also use a scope modifier to introduce the return type first:
my RETTYPE sub ( PARAMS ) TRAITS {...}
our RETTYPE sub ( PARAMS ) TRAITS {...}
In this case there is no effective difference, since the distinction between my and our is only in the handling of the name, and in the case of an anonymous sub, there's isn't one.
Trait is the name for a compile-time (is) property. See "Properties and traits".
You can declare a sub without parameter list, as in Perl 5:
sub foo {...}
This is equivalent to
sub foo (*@_, *%_) {...}
Positional arguments implicitly come in via the @_ array, but unlike in Perl 5 they are readonly aliases to actual arguments:
sub say { print qq{"@_[]"\n}; } # args appear in @_
sub cap { $_ = uc $_ for @_ } # Error: elements of @_ are read-only
Also unlike in Perl 5, Perl 6 has true named arguments, which come in via %_ instead of @_. (To construct pseudo-named arguments that come in via @_ as in Perl 5, the p5-to-p6 translator will use the ugly p5=> operator instead of Perl 6's => Pair constructor.)
If you need to modify the elements of @_ or %_, declare the array or hash explicitly with the is rw trait:
sub swap (*@_ is rw, *%_ is rw) { @_[0,1] = @_[1,0]; %_<status> = "Q:S"; }
Note: the "rw" container trait is automatically distributed to the individual elements by the the slurpy star even though there's no actual array or hash passed in. More precisely, the slurpy star means the declared formal parameter is not considered readonly; only its elements are. See "Parameters and arguments" below.
Note also that if the sub's block contains placeholder variables (such as $^foo or $:bar), those are considered to be formal parameters already, so in that case @_ or %_ fill the role of sopping up unmatched arguments. That is, if those containers are explicitly mentioned within the body, they are added as slurpy parameters. This allows you to easily customize your error message on unrecognized parameters. If they are not mentioned in the body, they are not added to the signature, and normal dispatch rules will simply fail if the signature cannot be bound.
From t/data_types/anon_block.t lines 12–18 (no results): (skip)
| L<S06/"Blocks"> |
| L<S04/"The Relationship of Blocks and Declarations"> |
| |
| =cut |
| |
| plan 32; |
| |
From t/data_types/anon_block.t lines 29–34 (2 √, 0 ×): (skip)
| # L<S06/"Blocks"> |
| # anon blocks |
| my $anon_block = { 1 }; |
√ | isa_ok($anon_block, 'Block'); |
√ | is($anon_block(), 1, '{} <anon block> works'); |
| |
From t/data_types/anon_block.t lines 54–108 (16 √, 1 ×): (skip)
| # L<S06/"Blocks"> |
| # bare blocks |
| |
| my $foo; |
| {$foo = "blah"}; |
√ | is($foo, "blah", "lone block actually executes it's content"); |
| |
| my $foo2; |
| {$foo2 = "blah"}; |
√ | is($foo2, "blah", "lone block w/out a semicolon actually executes it's content"); |
| |
| my $foo3; |
| ({$foo3 = "blah"}); |
× | ok(!defined($foo3), "block enclosed by parentheses should not auto-execute (1)", :todo<bug>); |
| |
| my $foo4; |
| ({$foo4 = "blah"},); |
√ | ok(!defined($foo4), "block enclosed by parentheses should not auto-execute (2)"); |
| |
| my ($one, $two); |
| # The try's here because it should die: $foo{...} should only work if $foo isa |
| # Hash (or sth. which provides appropriate tieing/&postcircumfix:<{ |
| # }>/whatever, but a Code should surely not support hash access). |
| # Additionally, a smart compiler will detect thus errors at compile-time, so I |
| # added an eval(). --iblech |
| try { eval '0,{$one = 1}{$two = 2}' }; |
√ | is($one, undef, 'two blocks ({} {}) no semicolon after either,.. first block does not execute'); |
√ | is($two, 2, '... but second block does (parsed as hash subscript)'); |
| |
| my ($one_a, $two_a); |
| {$one_a = 1}; {$two_a = 2} |
√ | is($one_a, 1, '... two blocks ({}; {}) semicolon after the first only,.. first block does execute'); |
√ | is($two_a, 2, '... and second block does too'); |
| |
| my ($one_b, $two_b); |
| { |
| $one_b = 1 |
| } |
| { |
| $two_b = 2 |
| }; |
√ | is($one_b, 1, '... two stand-alone blocks ({\n...\n}\n{\n...\n}),.. first block does execute'); |
√ | is($two_b, 2, '... and second block does too'); |
| |
| my ($one_c, $two_c); |
| {$one_c = 1}; {$two_c = 2}; |
√ | is($one_c, 1, '... two blocks ({}; {};) semicolon after both,.. first block does execute'); |
√ | is($two_c, 2, '... and second block does too'); |
| |
| sub f { { 3 } } |
√ | is(f(), 3, 'bare blocks immediately runs even as the last statement'); |
√ | is((sub { { 3 } }).(), 3, 'ditto for anonymous subs'); |
√ | is((sub { { { 3 } } }).(), 3, 'ditto, even if nested'); |
√ | dies_ok({(sub { { $^x } }).()}, 'implicit params become errors'); |
√ | isnt((sub { -> { 3 } }).(), 3, 'as are pointies'); |
Raw blocks are also executable code structures in Perl 6.
Every block defines an object of type Code, which may either be executed immediately or passed on as a Code object. How a block is parsed is context dependent.
A bare block where an operator is expected terminates the current expression and will presumably be parsed as a block by the current statement-level construct, such as an if or while. (If no statement construct is looking for a block there, it's a syntax error.) This form of bare block requires leading whitespace because a bare block where a postfix is expected is treated as a hash subscript.
A bare block where a term is expected merely produces a Code object. If the term bare block occurs in a list, it is considered the final element of that list unless followed immediately by a comma or colon (intervening \h* or "unspace" is allowed).
From t/spec/S02-whitespace_and_comments/unspace.t lines 175–190 (no results): (skip)
| # L<S06/"Blocks"/"unless followed immediately by a comma">
|
|
|
| sub baz(Code $x, *@y) { $x.(@y) }
|
|
|
| is(eval('baz { @^x }, 1, 2, 3'), (1, 2, 3), 'comma immediately following arg block');
|
| is(eval('baz { @^x } , 1, 2, 3'), (1, 2, 3), 'comma not immediately following arg block');
|
| is(eval('baz { @^x }\ , 1, 2, 3'), (1, 2, 3), 'unspace then comma following arg block');
|
|
|
| class Code is also {
|
| method xyzzy(Code $x: *@y) { $x.(@y) }
|
| }
|
|
|
| is(eval('xyzzy { @^x }: 1, 2, 3'), (1, 2, 3), 'colon immediately following arg block');
|
| is(eval('xyzzy { @^x } : 1, 2, 3'), (1, 2, 3), 'colon not immediately following arg block');
|
| is(eval('xyzzy { @^x }\ : 1, 2, 3'), (1, 2, 3), 'unspace then colon following arg block');
|
|
|
From t/data_types/anon_block.t lines 35–53 (9 √, 0 ×): (skip)
| # L<S06/""Pointy blocks""> |
| # pointy subs |
| my $pointy_block = -> { 1 }; |
√ | isa_ok($pointy_block, 'Block'); |
√ | is($pointy_block(), 1, '-> {} <"pointy" block> works'); |
| |
| my $pointy_block_w_arg = -> $arg { 1 + $arg }; |
√ | isa_ok($pointy_block_w_arg, 'Block'); |
√ | is($pointy_block_w_arg(3), 4, '-> $arg {} <"pointy" block w/args> works'); |
| |
| my $pointy_block_w_multiple_args = -> $arg1, $arg2 { $arg1 + $arg2 }; |
√ | isa_ok($pointy_block_w_multiple_args, 'Block'); |
√ | is($pointy_block_w_multiple_args(3, 4), 7, '-> $arg1, $arg2 {} <"pointy" block w/multiple args> works'); |
| |
| my $pointy_block_nested = -> $a { -> $b { $a + $b }}; |
√ | isa_ok($pointy_block_nested, Block); |
√ | isa_ok($pointy_block_nested(5), Block); |
√ | is $pointy_block_nested(5)(6), 11, '-> $a { -> $b { $a+$b }} nested <"pointy" block> works'; |
| |
From t/blocks/pointy.t lines 11–14 (no results): (skip)
| L<S06/""Pointy blocks""> |
| |
| =cut |
| |
Semantically the arrow operator -> is almost a synonym for the sub keyword as used to declare an anonymous subroutine, insofar as it allows you to declare a signature for a block of code. However, the parameter list of a pointy block does not require parentheses, and a pointy block may not be given traits. In most respects, though, a pointy block is treated more like a bare block than like an official subroutine. Syntactically, a pointy block may be used anywhere a bare block could be used:
From t/blocks/pointy.t lines 15–40 (5 √, 0 ×): (skip)
| # L<S06/""Pointy blocks""/the parameter list of a pointy block does not |
| # require parentheses> |
| my ($sub, $got); |
| |
| $got = ''; |
| $sub = -> $x { $got = "x $x" }; |
| $sub.(123); |
√ | is $got, 'x 123', 'pointy sub without param parens'; |
| |
| $got = ''; |
| $sub = -> ($x) { $got = "x $x" }.(123); |
√ | is $got, 'x 123', 'pointy sub with param parens dot called'; |
| |
| $got = ''; |
| $sub = -> ($x) { $got = "x $x" }(123); |
√ | is $got, 'x 123', 'pointy sub with param parens called'; |
| |
| $got = ''; |
| -> $x { $got = "x $x" }.(123); |
√ | is $got, 'x 123', 'called pointy immediately: -> $x { ... }.(...)'; |
| |
| $got = ''; |
| -> $x { $got = "x $x" }(123); |
√ | is $got, 'x 123', 'called pointy immediately: -> $x { ... }(...)'; |
| |
| |
my $sq = -> $val { $val**2 };
say $sq(10); # 100
my @list = 1..3;
for @list -> $elem {
say $elem; # prints "1\n2\n3\n"
}
It also behaves like a block with respect to control exceptions. If you return from within a pointy block, the block is transparent to the return; it will return from the innermost enclosing sub or method, not from the block itself. It is referenced by &?BLOCK, not &?ROUTINE.
From t/blocks/pointy.t lines 50–60 (0 √, 2 ×): (skip)
| # L<S06/""Pointy blocks""/behaves like a block with respect to control exceptions> |
| my $n = 1; |
| my $s = -> { |
| last if $n == 10; |
| $n++; |
| redo if $n < 10; |
| }; |
| try { $s.() }; |
× | is($!, undef, 'pointy with block control exceptions', :todo<feature>); |
× | is $n, 10, "pointy control exceptions ran", :todo<feature>; |
| |
From t/blocks/pointy.t lines 61–81 (3 √, 0 ×): (skip)
| # L<S06/""Pointy blocks""/will return from the innermost enclosing sub or method> |
| my $str = ''; |
| |
| sub outer { |
| my $s = -> { |
√ | is(&?ROUTINE.name, '&Main::outer', 'pointy still sees outer\'s &?ROUTINE'); |
| |
| $str ~= 'inner'; |
| return 'inner ret'; |
| }; |
| $s.(); |
| $str ~= 'outer'; |
| return 'outer ret'; |
| } |
| |
√ | is outer(), 'inner ret', 'return in pointy returns from enclosing sub'; |
√ | is $str, 'inner', 'return in pointy returns from enclosing sub'; |
| |
| # What about nested pointies -> { ... -> {} }? |
| |
| |
From t/blocks/pointy.t lines 82–83 (no results): (skip)
| # L<S06/""Pointy blocks""/It is referenced> |
| # Coming soon... |
A normal pointy block's parameters default to readonly, just like parameters to a normal sub declaration. However, the double-pointy variant defaults parameters to rw:
for @list <-> $elem {
$elem++;
}
This form applies rw to all the arguments:
for @kv <-> $key, $value {
$key ~= ".jpg";
$value *= 2 if $key ~~ :e;
}
To predeclare a subroutine without actually defining it, use a "stub block":
sub foo {...} # Yes, those three dots are part of the actual syntax
The old Perl 5 form:
sub foo;
is a compile-time error in Perl 6 (because it would imply that the body of the subroutine extends from that statement to the end of the file, as class and module declarations do). The only allowed use of the semicolon form is to declare a MAIN sub--see "Declaring a MAIN subroutine" below.
Redefining a stub subroutine does not produce an error, but redefining an already-defined subroutine does. If you wish to redefine a defined sub, you must explicitly use the "is instead" trait.
The ... is the "yadayadayada" operator, which is executable but returns a failure. You can also use ??? to produce a warning, or !!! to always die. These also officially define stub blocks if used as the only expression in the block.
It has been argued that ... as literal syntax is confusing when you might also want to use it for metasyntax within a document. Generally this is not an issue in context; it's never an issue in the program itself, and the few places where it could be an issue in the documentation, a comment will serve to clarify the intent, as above. The rest of the time, it doesn't really matter whether the reader takes ... as literal or not, since the purpose of ... is to indicate that something is missing whichever way you take it.
Subroutines and variables can be declared in the global namespace, and are thereafter visible everywhere in a program.
Global subroutines and variables are normally referred to by prefixing their identifiers with * (short for "GLOBAL::"). The * is required on the declaration unless the GLOBAL namespace can be inferred some other way, but the * may be omitted on use if the reference is unambiguous:
$*next_id = 0;
sub *saith($text) { print "Yea verily, $text" }
module A {
my $next_id = 2; # hides any global or package $next_id
saith($next_id); # print the lexical $next_id;
saith($*next_id); # print the global $next_id;
}
module B {
saith($next_id); # Unambiguously the global $next_id
}
However, under stricture (the default for most code), the * is required on variable references. It's never required on sub calls, and in fact, the syntax
$x = *saith($y);
is illegal, because a * where a term is expected is always parsed as the "whatever" token. If you really want to use a *, you must also use the sigil along with the twigil:
$x = &*saith($y);
Only the name is installed into the GLOBAL package by *. To define subs completely within the scope of the GLOBAL namespace you should use "package GLOBAL {...}" around the declaration.
From t/blocks/lvalue_subroutines.t lines 11–112 (4 √, 10 ×): (skip)
| L<S06/"Lvalue subroutines"> |
| |
| =cut |
| |
| # Lvalue subrefs |
| { |
| my $var1 = 1; |
| my $var2 = 2; |
| |
| my $lastvar = sub () is rw { return $var2 }; |
| my $prevvar = sub () is rw { return $lastvar() }; |
| |
| $lastvar() = 3; |
√ | is $var2, 3, "lvalue subroutine references work (simple)"; |
| |
| $prevvar() = 4; |
√ | is $var2, 4, "lvalue subroutine references work (nested)"; |
| } |
| |
| { |
| my $var = 42; |
| my $notlvalue = sub () { return $var }; |
| |
× | dies_ok { $notlvalue() = 23 }, |
| "assigning to non-rw subrefs should die", :todo<bug>; |
× | is $var, 42, |
| "assigning to non-rw subrefs shouldn't modify the original variable", :todo<bug>; |
| } |
| |
| { |
| my $var1 = 1; |
| my $var2 = 2; |
| |
| sub lastvar is rw { return $var2; } |
| sub prevvar is rw { return lastvar(); } |
| |
| lastvar() = 3; |
√ | is($var2, 3, "lvalue subroutines work (simple)"); |
| |
| prevvar() = 4; |
√ | is($var2, 4, "lvalue subroutines work (nested)"); |
| } |
| |
| { |
| my $var = 42; |
| |
| # S6 says that lvalue subroutines are marked out by 'is rw' |
| sub notlvalue { return $var; } # without rw |
| |
× | dies_ok { notlvalue() = 5 }, |
| "assigning to non-rw subs should die"; |
× | is $var, 42, |
| "assigning to non-rw subs shouldn't modify the original variable"; |
| } |
| |
| sub check ($passwd) { return $passwd eq "fish"; }; |
| |
| eval 'sub checklastval ($passwd) is rw { |
| my $proxy is Proxy( |
| FETCH => sub ($self) { |
| return lastval(); |
| }, |
| STORE => sub ($self, $val) { |
| die "wrong password" unless check($passwd); |
| lastval() = $val; |
| } |
| ); |
| return $proxy; |
| };'; |
| |
| my $errors; |
| eval 'try { checklastval("octopus") = 10 }; $errors=$!;'; |
× | is($errors, "wrong password", 'checklastval STORE can die', :todo<feature>); |
| |
| # Above test may well die for the wrong reason, if the Proxy stuff didn't |
| # parse OK, it will complain that it couldn't find the desired subroutine |
× | is(eval('checklastval("fish") = 12; $val2'), 12, 'proxy lvalue subroutine STORE works', :todo<feature>); |
| my $resultval; |
| eval '$resultval = checklastval("fish");'; |
× | is($resultval, 12, 'proxy lvalue subroutine FETCH works', :todo<feature>); |
| |
| my $realvar = "foo"; |
| sub proxyvar ($prefix) is rw { |
| return Proxy.new( |
| FETCH => { $prefix ~ lc($realvar) }, |
| STORE => { lc($realvar = $^val) }, |
| ); |
| } |
× | is try { proxyvar("PRE") }, 'PREfoo', 'proxy lvalue subroutine FETCH works', :todo<feature>; |
| # Return value of assignments of Proxy objects is decided now. |
| # See thread "Assigning Proxy objects" on p6l, |
| # L<"http://www.nntp.perl.org/group/perl.perl6.language/21838">. |
| # Quoting Larry: |
| # The intention is that lvalue subs behave in all respects as if they |
| # were variables. So consider what |
| # |
| # say $nonproxy = 40; |
| # |
| # should do. |
× | is try { proxyvar("PRE") = "BAR" }, 'BAR', |
| 'proxy lvalue subroutine STORE works and returns the correct value', :todo<feature>; |
× | is $realvar, 'BAR', 'variable was modified', :todo<feature>; |
Lvalue subroutines return a "proxy" object that can be assigned to. It's known as a proxy because the object usually represents the purpose or outcome of the subroutine call.
Subroutines are specified as being lvalue using the is rw trait.
An lvalue subroutine may return a variable:
my $lastval;
sub lastval () is rw { return $lastval }
or the result of some nested call to an lvalue subroutine:
sub prevval () is rw { return lastval() }
or a specially tied proxy object, with suitably programmed FETCH and STORE methods:
sub checklastval ($passwd) is rw {
return new Proxy:
FETCH => method {
return lastval();
},
STORE => method ($val) {
die unless check($passwd);
lastval() = $val;
};
}
Other methods may be defined for specialized purposes such as temporizing the value of the proxy.
From t/oo/methods/overload.t lines 7–72 (3 √, 6 ×): (skip)
| # L<S06/"Operator overloading"> |
| # Later, we want to run the same tests with two classes, Foo and Bar. |
| # Foo overloads the operators by using multi methods, Bar by using multi subs. |
| # But as currently both Foo and Bar do not compile, we have to create a |
| # stubclass, which is then given to &run_tests_with. |
| # But if the class does compile, $foo_class and $bar_class will be set to the |
| # correct classes (Foo and Bar), and the tests have a chance to succeed. |
| class StubClass {} |
| my ($foo_class, $bar_class) = (StubClass, StubClass); |
| |
| class Foo { |
| has $.bar is rw; |
| multi method prefix:<~> ($self) { return $.bar } |
| multi method infix:<+> ($a, $b) { return "$a $b" } |
| } |
| |
| $foo_class = Foo; |
| |
| class Bar { |
| has $.bar is rw; |
| } |
| |
| multi sub prefix:<~> (Bar $self) { return $self.bar } |
| multi sub infix:<+> (Bar $a, Bar $b) { return "$a $b" } |
| |
| $bar_class = Bar; |
| |
| run_tests_with($foo_class); |
| run_tests_with($bar_class); |
| |
| sub run_tests_with($class) { |
| { |
| my $val; |
√ | lives_ok { |
| my $foo = $class.new(); |
| $foo.bar = 'software'; |
| $val = "$foo" |
| }, '... class methods work for class', :todo<feature>; |
× | is($val, 'software', '... basic prefix operator overloading worked', :todo<feature>); |
| |
√ | lives_ok { |
| my $foo = $class.new(); |
| $foo.bar = 'software'; |
| $val = $foo + $foo; |
| }, '... class methods work for class', :todo<feature>; |
× | is($val, 'software software', '... basic infix operator overloading worked', :todo<feature>); |
| } |
| |
| # Test that the object is correctly stringified when it is in an array. |
| # And test that »...« automagically work, too. |
| { |
| my $obj; |
√ | lives_ok { |
| $obj = $class.new; |
| $obj.bar = "pugs"; |
| }, "instantiating a class which defines operators worked", :todo<feature>; |
| |
| my @foo = ($obj, $obj, $obj); |
| my $res; |
× | lives_ok { $res = ~@foo }, "stringification didn't die", :todo<feature>; |
× | is $res, "pugs pugs pugs", "stringification overloading worked in array stringification", :todo<feature>; |
| |
× | lives_ok { $res = ~[@foo »~« "!"] }, "stringification with hyperization didn't die", :todo<feature>; |
× | is $res, "pugs! pugs! pugs!", "stringification overloading was hyperized correctly", :todo<feature>; |
| } |
| } |
From t/operators/operator_overloading.t lines 11–121 (17 √, 5 ×): (skip)
| L<S06/"Operator overloading"> |
| |
| =cut |
| |
| # This set of tests is very basic for now. |
| |
| sub prefix:<X> ($thing) { return "ROUGHLY$thing"; }; |
| |
√ | is(X "fish", "ROUGHLYfish", |
| 'prefix operator overloading for new operator'); |
| |
| sub prefix:<±> ($thing) { return "AROUND$thing"; }; |
√ | is ± "fish", "AROUNDfish", 'prefix operator overloading for new operator (unicode)'; |
| sub prefix:<(+-)> ($thing) { return "ABOUT$thing"; }; |
× | is eval(q[ (+-) "fish" ]), "ABOUTfish", 'prefix operator overloading for new operator (nasty)', :todo<bug>; |
| |
| { |
| my sub prefix:<->($thing) { return "CROSS$thing"; }; |
√ | is(-"fish", "CROSSfish", |
| 'prefix operator overloading for existing operator (but only lexically so we don\'t mess up runtime internals (needed at least for PIL2JS, probably for PIL-Run, too)'); |
| } |
| |
| sub infix:<×> ($a, $b) { $a * $b } |
√ | is(5 × 3, 15, "infix Unicode operator"); |
| |
| sub infix:<C> ($text, $owner) { return "$text copyright $owner"; }; |
√ | is "romeo & juliet" C "Shakespeare", "romeo & juliet copyright Shakespeare", |
| 'infix operator overloading for new operator'; |
| |
| sub infix:<©> ($text, $owner) { return "$text Copyright $owner"; }; |
√ | is "romeo & juliet" © "Shakespeare", "romeo & juliet Copyright Shakespeare", |
| 'infix operator overloading for new operator (unicode)'; |
| |
| sub infix:<(C)> ($text, $owner) { return "$text CopyRight $owner"; }; |
× | is eval(q[ "romeo & juliet" (C) "Shakespeare" ]), "romeo & juliet CopyRight Shakespeare", |
| 'infix operator overloading for new operator (nasty)', :todo<bug>; |
| |
| sub infix:«_<_»($one, $two) { return 42 } |
√ | is 3 _<_ 5, 42, "frenchquoted infix sub"; |
| |
| sub postfix:<W> ($wobble) { return "ANDANDAND$wobble"; }; |
| |
√ | is("boop" W, "ANDANDANDboop", |
| 'postfix operator overloading for new operator'); |
| |
| sub postfix:<&&&&&> ($wobble) { return "ANDANDANDANDAND$wobble"; }; |
√ | is("boop"&&&&&, "ANDANDANDANDANDboop", |
| "postfix operator overloading for new operator (weird)"); |
| |
| my $var = 0; |
× | ok(eval('macro circumfix:{"<!--","-->"} ($text) is parsed / .*? / { "" }; <!-- $var = 1; -->; $var == 0;'), 'circumfix macro {"",""}', :todo<feature>); |
× | ok(eval('macro circumfix:«<!-- -->» ($text) is parsed / .*? / { "" }; <!-- $var = 1; -->; $var == 0;'), 'circumfix macro «»', :todo<feature>); |
| |
| # demonstrate sum prefix |
| |
| { |
| my sub prefix:<Σ> (@x) { [+] @x } |
√ | is(Σ [1..10], 55, "sum prefix operator"); |
| } |
| |
| # check that the correct overloaded method is called |
| multi postfix:<!> ($x) { [*] 1..$x } |
| multi postfix:<!> (Str $x) { return($x.uc ~ "!!!") } |
| |
√ | is(10!, 3628800, "factorial postfix operator"); |
× | is("boobies"!, "BOOBIES!!!", "correct overloaded method called"); |
| |
| # Overloading by setting the appropriate code variable |
| { |
| my &infix:<plus>; |
| BEGIN { |
| &infix:<plus> := { $^a + $^b }; |
| } |
| |
√ | is 3 plus 5, 8, 'overloading an operator using "my &infix:<...>" worked'; |
| } |
| |
| # Overloading by setting the appropriate code variable using symbolic |
| # dereferentiation |
| { |
| my &infix:<times>; |
| BEGIN { |
| &::("infix:<times>") := { $^a * $^b }; |
| } |
| |
√ | is 3 times 5, 15, 'operator overloading using symbolic dereferentiation'; |
| } |
| |
| # Accessing an operator using its subroutine name |
| { |
√ | is &infix:<+>(2, 3), 5, "accessing a builtin operator using its subroutine name"; |
| |
| my &infix:<z> := { $^a + $^b }; |
√ | is &infix:<z>(2, 3), 5, "accessing a userdefined operator using its subroutine name"; |
| |
√ | is ~(&infix:<»+«>([1,2,3],[4,5,6])), "5 7 9", "accessing a hyperoperator using its subroutine name"; |
| } |
| |
| # Overriding infix:<;> |
| { |
| my proto infix:<;> ($a, $b) { $a + $b } |
√ | is (3 ; 2), 5 # XXX correct? |
| } |
| |
| # [NOTE] |
| # pmichaud ruled that prefix:<;> and postfix:<;> shouldn't be defined by |
| # the synopses: |
| # http://colabti.de/irclogger/irclogger_log/perl6?date=2006-07-29,Sat&sel=189#l299 |
| # so we won't test them here. |
| |
| # Overriding prefix:<if> |
From t/operators/recursive_definition.t lines 7–16 (2 √, 0 ×): (skip)
√ | #L<S06/Operator overloading> |
| eval q{{ |
| sub postfix:<!>($arg) { |
| if ($arg == 0) { 1;} |
| else { ($arg-1)! * $arg;} |
| } |
| |
| ok(5! == 120, "recursive factorial works"); |
| }} or flunk("recursive factorial works"); |
√ | is($!, undef, "recursive factorial parses"); |
Operators are just subroutines with special names and scoping. An operator name consists of a grammatical category name followed by a single colon followed by an operator name specified as if it were a hash subscript (but evaluated at compile time). So any of these indicates the same binary addition operator:
infix:<+>
infix:«+»
infix:<<+>>
infix:{'+'}
infix:{"+"}
Use the & sigil just as you would on ordinary subs.
Unary operators are defined as prefix or postfix:
sub prefix:<OPNAME> ($operand) {...}
sub postfix:<OPNAME> ($operand) {...}
Binary operators are defined as infix:
sub infix:<OPNAME> ($leftop, $rightop) {...}
Bracketing operators are defined as circumfix where a term is expected or postcircumfix where a postfix is expected. A two-element slice containing the leading and trailing delimiters is the name of the operator.
sub circumfix:<LEFTDELIM RIGHTDELIM> ($contents) {...}
sub circumfix:{'LEFTDELIM','RIGHTDELIM'} ($contents) {...}
Contrary to Apocalypse 6, there is no longer any rule about splitting an even number of characters. You must use a two-element slice. Such names are canonicalized to a single form within the symbol table, so you must use the canonical name if you wish to subscript the symbol table directly (as in PKG::{'infix:<+>'}). Otherwise any form will do. (Symbolic references do not count as direct subscripts since they go through a parsing process.) The canonical form always uses angle brackets and a single space between slice elements. The elements are not escaped, so PKG::circumfix:{'<','>'} is canonicalized to PKG::{'circumfix:<< >>'}, and decanonicalizing always involves stripping the outer angles and splitting on space, if any. This works because a hash key knows how long it is, so there's no ambiguity about where the final angle is. And space works because operators are not allowed to contain spaces.
Operator names can be any sequence of non-whitespace characters including Unicode characters. For example:
sub infix:<(c)> ($text, $owner) { return $text but Copyright($owner) }
method prefix:<±> (Num $x --> Num) { return +$x | -$x }
multi sub postfix:<!> (Int $n) { $n < 2 ?? 1 !! $n*($n-1)! }
macro circumfix:«<!-- -->» ($text) is parsed / .*? / { "" }
my $document = $text (c) $me;
my $tolerance = ±7!;
<!-- This is now a comment -->
Whitespace may never be part of the name (except as separator within a <...> or «...» slice subscript, as in the example above).
A null operator name does not define a null or whitespace operator, but a default matching subrule for that syntactic category, which is useful when there is no fixed string that can be recognized, such as tokens beginning with digits. Such an operator must supply an is parsed trait. The Perl grammar uses a default subrule for the :1st, :2nd, :3rd, etc. regex modifiers, something like this:
sub regex_mod_external:<> ($x) is parsed(token { \d+[st|nd|rd|th] }) {...}
Such default rules are attempted in the order declared. (They always follow any rules with a known prefix, by the longest-token-first rule.)
Although the name of an operator can be installed into any package or lexical namespace, the syntactic effects of an operator declaration are always lexically scoped. Operators other than the standard ones should not be installed into the * namespace. Always use exportation to make non-standard syntax available to other scopes.
From t/syntax/signature.t lines 90–143 (7 √, 0 ×): (skip)
| # L<S06/"Parameters and arguments"> |
| { |
| # let's start with valid signatures whose canonical stringy form looks |
| # just like their source. I incidentally use different sigils, can't |
| # throw in the complete cartesian product here... |
| my @sigs = |
| ( ':($x)', 'single required positional' |
| , ':($x:)', 'invocant only' |
| , ':(@x, $y)', 'two required positionals' |
| , ':($x, %y?)', 'required and optional positionals' |
| , ':($x is rw is ref is lazy is moose)', # note order matters :/ |
| 'traits (including user defined)' |
| , ':($x, $y, :$z)', 'positional and named' |
| , ':($x, $y?, :$z)', 'optional positional and named' |
| , ':(:$x)', 'required named' |
| , ':(:$x?)', 'optional named' |
| , ':(:short($long))', 'long named' |
| , ':(:short($long)?)', 'optional long named' |
| , ':($ : %x)', 'dummy invocant' |
| , ':($x :($y))', 'unpacking(1)' |
| , ':($x :($y: $z))', 'unpacking(2)' |
| , # add more here. |
| # We parse these correctly but don't pretty print them correctly yet. |
| , ':($x = 42)', 'positional with default' |
| , ':(@x = (1, 2))', 'positional array with default' |
| , ':(%x = (1 => 2))', 'positional hash with default' |
| , ':(:$x = 42)', 'named with default' |
| , ':(:@x = (1, 2))', 'named array with default' |
| , ':(:%x = (1 => 2))', 'named hash with default' |
| , ':(:x($y) = 42)', 'longnamed with default' |
| , ':(:x(@y) = (1, 2))', 'longnamed array with default' |
| , ':(:x(%y) = (1 => 2))', 'longnamed hash with default' |
| ); |
| for @sigs -> $sig, $desc { |
√ | is eval("my \$s = $sig; qq[\$s]"), $sig, "signature stringifies - $desc"; |
| } |
| |
| # ("" ~ :() is just an interim hack to dispatch into pretty-newval. will be removed.) |
| # canonized version is different from source |
√ | is eval('""~:($x!)'), ':($x)', 'required positional with hint'; |
√ | is eval('""~:($x? = 42)'), ':($x = 42)', 'positional with default and hint'; |
√ | is eval('""~:(@y? = (1, 2))'), ':(@y = (1, 2))', |
| 'named array with default and hint'; |
| |
√ | is eval('""~:($x is rw is ro is rw is copy is ro is rw)'), |
| ':($x is rw)', 'last repeated trait wins'; # XXX: spec |
√ | is eval('""~:($x is moose is ref is ro is lazy)'), # 'is ro' is default thus not printed |
| ':($x is ref is lazy is moose)', |
| 'interleaved traits'; # XXX spec this minor point? |
| |
| |
| # should die |
√ | eval_dies_ok ':($x! = 42)', "required params can't have a default"; |
| } |
Perl 6 subroutines may be declared with parameter lists.
By default, all parameters are readonly aliases to their corresponding arguments--the parameter is just another name for the original argument, but the argument can't be modified through it. This is vacuously true for value arguments, since they may not be modified in any case. However, the default forces any container argument to also be treated as an immutable value. This extends down only one level; an immutable container may always return an element that is mutable if it so chooses. (For this purpose a scalar variable is not considered a container of its singular object, though, so the top-level object within a scalar variable is considered immutable by default. Perl 6 does not have references in the same sense that Perl 5 does.)
To allow modification, use the is rw trait. This requires a mutable object or container as an argument (or some kind of protoobject that can be converted to a mutable object, such as might be returned by an array or hash that knows how to autovivify new elements). Otherwise the signature fails to bind, and this candidate routine cannot be considered for servicing this particular call. (Other multi candidates, if any, may succeed if the don't require rw for this parameter.) In any case, failure to bind does not by itself cause an exception to be thrown; that is completely up to the dispatcher.
To pass-by-copy, use the is copy trait. An object container will be cloned whether or not the original is mutable, while an (immutable) value will be copied into a suitably mutable container. The parameter may bind to any argument that meets the other typological constraints of the parameter.