declarator multi

Documentation for declarator multi, assembled from the following types:

language documentation Functions

From Functions

(Functions) declarator multi

Perl 6 allows you to write several routines with the same name but different signatures. When the routine is called by name, the runtime environment determines the proper candidate and calls it.

You declare each candidate with the multi declarator:

multi congratulate($name{
    say "Happy birthday, $name";
}
multi congratulate($name$age{
    say "Happy {$age}th birthday, $name";
}
 
congratulate 'Larry';       # OUTPUT: «Happy birthday, Larry␤» 
congratulate 'Bob'45;     # OUTPUT: «Happy 45th birthday, Bob␤» 

Dispatch can happen on the number of arguments (the arity), the type of arguments but also on additional assertions which can be placed on them. For more information about type constraints see the documentation for the Signature class.

multi as-json(Bool $d{ $d ?? 'true' !! 'false'}
multi as-json(Real $d{ ~$d }
multi as-json(@d)      { sprintf '[%s]'@d.map(&as-json).join(''}
 
say as-json([True42]);    # OUTPUT: «[true, 42]␤» 

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.

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:

class Congrats {
    multi method congratulate($reason$name{
        say "Hooray for your $reason$name";
    }
}
 
role BirthdayCongrats {
    multi method congratulate('birthday'$name{
        say "Happy birthday, $name";
    }
    multi method congratulate('birthday'$name$age{
        say "Happy {$age}th birthday, $name";
    }
}
 
my $congrats = Congrats.new does BirthdayCongrats;
 
$congrats.congratulate('promotion','Cindy'); # OUTPUT: «Hooray for your promotion, Cindy␤» 
$congrats.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 $reasonStr $name|{*}
multi congratulate($reason$name{
   say "Hooray for your $reason$name";
}
multi congratulate($reason$nameInt $rank{
   say "Hooray for your $reason$name -- got rank $rank!";
}
 
congratulate('being a cool number''Fred');     # OK 
congratulate('being a cool number''Fred'42); # OK 
    congratulate('being a cool number'42);         # Proto match error 

The proto insists that all multi congratulate 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 &congratulate.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 unsuccessful 
proto notify(Str $user,Str $msg{
   my \hour = DateTime.now.hour;
   if hour > 8 or hour < 22 {
      return {*};
   } else {
      # we can't notify someone when they might be sleeping 
      return False;
   }
}

{*} 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() $strInt $number = 42{*}
multi mistake-proto($str$number{ say $str.^name }
mistake-proto(742);  # OUTPUT: «Int␤» -- not passed on 
mistake-proto('test'); # fails -- not passed on