syntax multi
Documentation for syntax multi
assembled from the following types:
language documentation Functions
From Functions
(Functions) declarator multi multi
Perl 6 allows for writing several routines with the same name but different signatures. When the routine is called by name, the runtime environment determines the proper candidate and invokes it.
Each candidate is declared with the multi
keyword. Dispatch happens depending on the number (arity), type and name of arguments. Consider the following example:
# version 1multi happy-birthday( )# version 2multi happy-birthday( , )# version 3multi happy-birthday( :, :, : = 'Mr' )# calls version 1 (arity)happy-birthday 'Larry'; # OUTPUT: «Happy Birthday Larry !»# calls version 2 (arity)happy-birthday 'Luca', 40; # OUTPUT: «Happy 40th Birthday Luca !»# calls version 3# (named arguments win against arity)happy-birthday( age => '50', name => 'John' ); # OUTPUT: «Happy 50th Birthday Mr John !»# calls version 2 (arity)happy-birthday( 'Jack', 25 ); # OUTPUT: «Happy 25th Birthday Jack !»
The first two versions of the happy-birthday
sub differs only in the arity (number of arguments), while the third version uses named arguments and is chosen only when named arguments are used, even if the arity is the same of another multi
candidate.
When two sub have the same arity, the type of the arguments drive the dispatch; when there are named arguments they drive the dispatch even when their type is the same as another candidate:
multi happy-birthday( Str , Int )multi happy-birthday( Str , Str )multi happy-birthday( Str :, Int : )happy-birthday 'Luca', 40; # OUTPUT: «Happy 40th Birthday Luca !»happy-birthday 'Luca', 'Mr'; # OUTPUT: «Happy Birthday Mr Luca !»happy-birthday age => 40, name => 'Luca'; # OUTPUT: «Happy Birthday Luca, you turned 40 !»
Named parameters participate in the dispatch even if they are not provided in the call. Therefore a multi candidate with named parameters will be given precedence.
For more information about type constraints see the documentation for the Signature class.
multi as-json(Bool )multi as-json(Real )multi as-json()say as-json( True ); # OUTPUT: «true»say as-json( 10.3 ); # OUTPUT: «10.3»say as-json( [ True, 10.3, False, 24 ] ); # OUTPUT: «[true, 10.3, false, 24]»
multi
without any specific routine type always defaults to a sub
, but you can use it on methods as well. The candidates are all the multi methods of the object:
my = Congrats.new does BirthdayCongrats;.congratulate('promotion','Cindy'); # OUTPUT: «Hooray for your promotion, Cindy».congratulate('birthday','Bob'); # OUTPUT: «Happy birthday, Bob»
Unlike sub
, if you use named parameters with multi methods, the parameters must be required parameters to behave as expected.
Please note that a non-multi sub or operator will hide multi candidates of the same name in any parent scope or child scope. The same is true for imported non-multi candidates.
proto
proto
is a way to formally declare commonalities between multi
candidates. It acts as a wrapper that can validate but not modify arguments. Consider this basic example:
proto congratulate(Str , Str , |)multi congratulate(, )multi congratulate(, , Int )congratulate('being a cool number', 'Fred'); # OKcongratulate('being a cool number', 'Fred', 42); # OK
congratulate('being a cool number', 42); # Proto match error
The proto insists that all multi congratulate
subs conform to the basic signature of two strings, optionally followed by further parameters. The |
is an un-named Capture
parameter, and allows a multi
to take additional arguments. The first two calls succeed, but the third fails (at compile time) because 42
doesn't match Str
.
say .signature # OUTPUT: «(Str $reason, Str $name, | is raw)»
You can give the proto
a function body, and place the {*}
where you want the dispatch to be done.
# attempts to notify someone -- False if unsuccessfulproto notify(Str , Str )
{*}
always dispatches to candidates with the parameters it's called with. Parameter defaults and type coercions will work but are not passed on.
proto mistake-proto(Str() , Int = 42)multi mistake-proto(, )mistake-proto(7, 42); # OUTPUT: «Int» -- not passed on
mistake-proto('test'); # fails -- not passed on