class Sub is Routine { }
A type for subroutines and operators. Subs are created with the sub
declarator keyword followed by an optional identifier. This short tutorial explains how operators are declared. For details of a sub's parameter list, see Signature
.
Note that subs that go by the same name as coercers will not take precedence over them. Use the &
-sigil to call them.
sub Int(Str $s){'what?'}; say [Int, Int('42'),&Int('42')]; # OUTPUT: «[(Int) 42 what?]»
Subs can be nested and scoped with my
and our
, whereby my
is the default. A sub declared with my
cannot be reached from any outer scope. An our
scoped sub will not redefine a sub of the same name in the outer scope. Any sub can be accessed via a closure from any outer scope. For instance, in this example
sub can-be-seener( $whatever ) { my sub can-be-seen ( $objection ) { return $whatever but $objection; } return &can-be-seen } my $objectioner = can-be-seener( "Really?"); say $objectioner(42).Int; # OUTPUT: «42»
$objectioner
will contain the can-be-seen
subroutine, even if it has been declared in another scope; calling it with 42
will return "Really?"
with the number 42 mixed in, as shown in the last sentence.
Operators§
Operators are also Sub
s. Their definition includes the category they belong to and their code, precedence and associativity. The syntax used in their definition is an example of extended identifiers.
Traits §
A Trait
is a sub that is applied at compile time to various objects like classes, routines or containers. It is declared with the trait_mod
declarator followed by a colon and a string literal containing the name of the trait. A single positional parameter defines the type of the object that the trait is applied to. A single named argument defines the secondary name and may carry arguments when the trait is called. Traits are a special grammar category and are allowed to be placed after most language object names or parameter lists.
say 'start'; multi trait_mod:<is>(Sub $s, :$foo){ say "⟨is foo⟩ has been called with ⟨$foo⟩ on {$s.WHICH}"; } sub bar() is foo<oi‽> { say 'bar has been called' } bar(); # OUTPUT: «⟨is foo⟩ has been called with ⟨oi‽⟩ on Sub|47563000startbar has been called»
Use destructuring to call traits with complex arguments.
multi trait_mod:<is>(Variable $a, :@foo [$firstpos, *@restpos, :$named, *%restnameds]) { say [$firstpos, @restpos, $named, %restnameds] } my $x is foo[1,2,3,:named<a>, :2b, :3c] = 1 # OUTPUT: «[1 [2 3] a {b => 2, c => 3}]»
Despite its funky syntax, a trait is just a normal Sub
. We can apply traits to it (or even themselves) and we can apply traits to objects at runtime.
multi trait_mod:<is> (Sub $s, :$foo) is foo { say 'is foo called' } sub bar {} &trait_mod:<is>(&bar, :foo); # OUTPUT: «is foo calledis foo called»