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 );say [Int, Int('42'),('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( ) my = can-be-seener( "Really?");say (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 sub trait_mod:<is>(Sub , :)sub bar() is foo<oi‽> 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 , : [, *, :, *]) my 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 sub trait_mod:<is> (Sub , :) is foo sub bar :<is>(, :foo);# OUTPUT: «is foo calledis foo called»
Type Graph §
Routines supplied by class Routine §
Sub inherits from class Routine, which provides the following routines:
(Routine) method name §
method name(Routine: --> Str)
Returns the name of the sub or method.
(Routine) method package §
method package(Routine:)
Returns the package in which the routine is defined.
(Routine) method multi §
method multi(Routine: --> Bool)
Returns True
if the routine is a multi sub or method. Note that the name of a multi sub refers to its proto
and this method would return false if called on it. It needs to be called on the candidates themselves:
multi foo ($, $) ;say .multi; # OUTPUT: «False» say .candidates».multi; # OUTPUT: «(True)»
(Routine) method candidates §
method candidates(Routine: --> Positional)
Returns a list of multi candidates, or a one-element list with itself if it's not a multi
(Routine) method cando §
method cando(Capture )
Returns a possibly-empty list of candidates that can be called with the given Capture, ordered by narrowest candidate first. For methods, the first element of the Capture needs to be the invocant:
.signature.say for "foo".^can("comb")[0].cando: \(Cool, "o");# OUTPUT: «(Cool $: Str $matcher, $limit = Inf, *%_)»
(Routine) method wrap §
method wrap(Routine: )
Wraps (i.e. in-place modifies) the routine. That means a call to this routine first calls &wrapper
, which then can (but doesn't have to) call the original routine with the callsame
, callwith
, nextsame
and nextwith
dispatchers. The return value from the routine is also the return value from the wrapper.
wrap
returns an instance of a private class called Routine::WrapHandle
, which you can pass to unwrap to restore the original routine.
(Routine) method unwrap §
method unwrap()
Restores the original routine after it has been wrapped with wrap. While the signature allows any type to be passed, only the Routine::WrapHandle
type returned from wrap
can usefully be.
(Routine) method is-wrapped §
Defined as:
method is-wrapped()
Returns True
or False
, depending on the whether or not the Routine
is wrapped.
(Routine) method yada §
method yada(Routine: --> Bool)
Returns True
if the routine is a stub
say (sub f() ).yada; # OUTPUT: «True» say (sub g() ).yada; # OUTPUT: «False»
(Routine) trait is cached §
multi sub trait_mod:<is>(Routine , :!)
Causes the return value of a routine to be stored, so that when subsequent calls with the same list of arguments are made, the stored value can be returned immediately instead of re-running the routine.[1]
Useful when storing and returning the computed value is much faster than re-computing it every time, and when the time saved trumps the cost of the use of more memory.
Even if the arguments passed to the routine are "reference types" (such as objects or arrays), then for the purpose of caching they will only be compared based on their contents. Thus the second invocation will hit the cache in this case:
say foo( [1, 2, 3] ); # runs foo say foo( [1, 2, 3] ); # doesn't run foo, uses cached value
Since it's still at the experimental stage, you will have to insert the use experimental :cached;
statement in any module or script that uses it.
use experimental :cached; sub nth-prime(Int where * > 0) is cached say nth-prime(43);say nth-prime(43);say nth-prime(43);
produces this output:
Calculating 43th prime 191 191 191
(Routine) trait is pure §
multi sub trait_mod:<is>(Routine , :!)
Marks a subroutine as pure, that is, it asserts that for the same input, it will always produce the same output without any additional side effects.
The is pure
trait is a promise by the programmer to the compiler that it can constant-fold calls to such functions when the arguments are known at compile time.
sub syllables() is pure
You can mark function as pure even if they throw exceptions in edge cases or if they modify temporary objects; hence the is pure
trait can cover cases that the compiler cannot deduce on its own. On the other hand, you might not want to constant-fold functions that produce a large return value (such as the string or list repetition operators, infix x
and xx
) even if they are pure, to avoid large precompilation files.
To see it an action with a particular compiler you can try this example:
BEGIN say ‘Start’;say (^100).map: ; # Example output: # Begin # Generating syllables # Start # (matiroi yeterani shoriyuru...
Essentially this allows the compiler to perform some operations at compile time. The benefits of constant-folding may include better performance, especially in cases when the folded code is precompiled.
In addition, using a pure function or operator in sink context (that is, where the result is discarded) may lead to a warning. The code
sub double() is pure ;double(21);say "anything";# WARNING: «Useless use of "double(21)" in expression "double(21)" in sink context (line 2)»
If you want to apply this trait to a multi
, you need to apply it to the proto
; it will not work otherwise, at least in versions 2018.08 and below.
(Routine) trait is rw §
multi sub trait_mod:<is>(Routine , :!)
When a routine is modified with this trait, its return value will be writable. This is useful when returning variables or writable elements of hashes or arrays, for example:
sub walk(\thing, *) is rw my ;walk(, 'some', 'key', 1, 2) = 'autovivified'; say .raku;
produces
("some" => ).hash
Note that return
marks return values as read only; if you need an early exit from an is rw
routine, you have to use return-rw
instead.
(Routine) trait is export §
multi sub trait_mod:<is>(Routine , :!)
Marks a routine as exported to the rest of the world
import Foo; # makes sub double available say double 21; # 42
From inside another file you'd say use Foo;
to load a module and import the exported functions.
See Exporting and Selective Importing Modules for more details.
(Routine) trait is DEPRECATED §
multi sub trait_mod:<is>(Routine , :!)
Marks a routine as deprecated, optionally with a message what to use instead.
This code
sub f() is DEPRECATED('the literal 42') say f();
produces this output:
42 Saw 1 occurrence of deprecated code. ================================================================================ Sub f (from GLOBAL) seen at: deprecated.p6, line 2 Please use the literal 42 instead. -------------------------------------------------------------------------------- Please contact the author to have these occurrences of deprecated code adapted, so that this message will disappear!
(Routine) trait is hidden-from-backtrace §
multi sub trait_mod:<is>(Routine, :!)
Hides a routine from showing up in a default backtrace. For example
sub inner ;sub outer ;outer();
produces the error message and backtrace
OH NOEZ in sub inner at bt.p6:1 in sub outer at bt.p6:2 in block <unit> at bt.p6:3
but if inner
is marked with hidden-from-backtrace
sub inner is hidden-from-backtrace ;sub outer ;outer();
the error backtrace does not show it:
OH NOEZ in sub outer at bt.p6:2 in block <unit> at bt.p6:3
(Routine) trait is default §
Defined as
multi sub trait_mod:<is>(Routine , :!)
There is a special trait for Routine
s called is default
. This trait is designed as a way to disambiguate multi
calls that would normally throw an error because the compiler would not know which one to use. This means that given the following two Routine
s, the one with the is default
trait will be called.
multi sub f() is default multi sub f() f(); # OUTPUT: «"Hello there"»
The is default
trait can become very useful for debugging and other uses but keep in mind that it will only resolve an ambiguous dispatch between two Routine
s of the same precedence. If one of the Routine
s is narrower than another, then that one will be called. For example:
multi sub f() is default multi sub f(:) f(); # "Use of uninitialized value $greet..."
In this example, the multi
without is default
was called because it was actually narrower than the Sub
with it.
(Routine) trait is raw §
Defined as:
multi sub trait_mod:<is>(Routine , :!)
Gives total access to the data structure returned by the routine.
my = <zape zapatilla>;sub þor() is raw ;þor()[1] = 'pantuflo';say ; # OUTPUT: «[zape pantuflo]»
Routines supplied by class Code §
Sub inherits from class Code, which provides the following routines:
(Code) method ACCEPTS §
multi method ACCEPTS(Code: Mu )
Usually calls the code object and passes $topic
as an argument. However, when called on a code object that takes no arguments, the code object is invoked with no arguments and $topic
is dropped. The result of the call is returned.
(Code) method arity §
Defined as:
method arity(Code: --> Int)
Returns the minimum number of positional arguments that must be passed in order to call the code object. Any optional or slurpy parameters in the code object's Signature
do not contribute, nor do named parameters.
sub argless() sub args(, ?) sub slurpy(, , *) say .arity; # OUTPUT: «0» say .arity; # OUTPUT: «1» say .arity; # OUTPUT: «2»
(Code) method assuming §
method assuming(Callable : |primers)
Returns a Callable
that implements the same behavior as the original, but has the values passed to .assuming
already bound to the corresponding parameters.
my sub slow(); # takes only one parameter and as such wont forward $n sub bench(); say .assuming(10000000).; # OUTPUT: «(10000000 7.5508834)»
For a sub with arity greater than one, you can use Whatever
*
for all of the positional parameters that are not "assumed".
sub first-and-last ( , ) my = .assuming( *, 'Smith' ); .( 'Joe' ); # OUTPUT: «Name is Joe Smith»
You can handle any combination of assumed and not assumed positional parameters:
sub longer-names ( , , , ) my = .assuming( *, *, 'Public', * ); .( 'Joe', 'Q.', 'Jr.'); # OUTPUT: «Name is Joe Q. Public Jr.»
Named parameters can be assumed as well:
sub foo .assuming(13, :42foo)(24, :72bar); # OUTPUT: «13 24 42 72»
And you can use .assuming
on all types of Callables, including Methods and Blocks:
# We use a Whatever star for the invocant: my = Str.^lookup('comb').assuming: *, /P \w+/;say comber 'Perl is awesome! Python is great! And PHP is OK too';# OUTPUT: «(Perl Python PHP)» my = .assuming: 'Raku';say learner :6months; # OUTPUT: «It took me 6 months to learn Raku»
(Code) method count §
Defined as:
method count(Code: --> Real)
Returns the maximum number of positional arguments that may be passed when calling the code object. For code objects that can accept any number of positional arguments (that is, they have a slurpy parameter), count
will return Inf
. Named parameters do not contribute.
sub argless() sub args(, ?) sub slurpy(, , *) say .count; # OUTPUT: «0» say .count; # OUTPUT: «2» say .count; # OUTPUT: «Inf»
(Code) method of §
Defined as:
method of(Code: --> Mu)
Returns the return type constraint of the Code
:
say -> () --> Int .of; # OUTPUT: «(Int)»
(Code) method signature §
Defined as:
multi method signature(Code: --> Signature)
Returns the Signature
object for this code object, which describes its parameters.
sub a(Int , Str ) ;say .signature; # OUTPUT: «(Int $one, Str $two)»
(Code) method cando §
method cando(Capture )
Returns a list of candidates that can be called with the given Capture. Since Code
objects do not have any multiple dispatch, this either returns a list with the object, or an empty list.
my = \'a'; # a single argument Capture my = \('a', 42); # a two argument Capture my = ; # a Block object, that is a subclass of Code, taking one argument say .cando(); # OUTPUT: «(-> $a { #`(Block|94212856419136) ... })» say .cando(); # OUTPUT: «()»
(Code) method Str §
Defined as:
multi method Str(Code: --> Str)
Will output the method name, but also produce a warning. Use .raku
or .gist
instead.
sub marine() say ~;# OUTPUT: «Sub object coerced to string (please use .gist or .raku to do that)marine» say .Str;# OUTPUT: «Sub object coerced to string (please use .gist or .raku to do that)marine» say .raku; # OUTPUT: «sub marine { #`(Sub|94280758332168) ... }»
(Code) method file §
Defined as:
method file(Code: --> Str)
Returns the name of the file in which the code object was declared.
say :<+>.file; # OUTPUT: «SETTING::src/core.c/Numeric.pm6»
(Code) method line §
Defined as
method line(Code: --> Int)
Returns the line number in the source code at which the code object's declaration begins.
say :<+>.line; # OUTPUT: «208»
If the code object was generated automatically (and thus not declared in the source code), then line
returns the line on which the enclosing scope's declaration begins. For example, when called on an automatically generated accessor method produced by the has $.name
syntax, line
returns the line on which the method's class's declaration begins.
For example, if you have the following source file:
# Line 5
Then the line
method would give you the following output:
say Food.^lookup('eat').line; # OUTPUT: «4» say Food.^lookup('ingredients').line; # OUTPUT: «1»
(Code) method is-implementation-detail §
method is-implementation-detail(--> False)
Note: this method has been available in Rakudo compiler starting from 2020.05 release.
Returns True
if the code object was marked with is implementation-detail
trait, False
otherwise.
Routines supplied by role Callable §
Sub inherits from class Code, which does role Callable, which provides the following routines:
(Callable) method CALL-ME §
method CALL-ME(Callable : |arguments)
This method is required for the ( )
postcircumfix operator and the .( )
postcircumfix operator. It's what makes an object actually call-able and needs to be overloaded to let a given object act like a routine. If the object needs to be stored in a &
-sigiled container, it has to implement Callable.
does Callable my = A;say a(); # OUTPUT: «called»
Applying the Callable
role is not a requirement to make an object callable; if a class simply wants to add subroutine-like semantics in a regular scalar container, the submethod CALL-ME
can be used for that.
my = A.new: values => [4,5,6,7];say (2); # OUTPUT: «6»
(Callable) method Capture §
Defined as:
method Capture()
Throws X::Cannot::Capture
.