declarator proto

Documentation for declarator proto assembled from the following types:

language documentation Functions

From Functions

(Functions) declarator 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 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 &congratulate.signature # OUTPUT: «(Str $reason, Str $name, | is raw)␤» 

You can give the proto a function body, and place the {*} (note there is no whitespace inside the curly braces) where you want the dispatch to be done. This can be useful when you have a "hole" in your routine that gives it different behavior depending on the arguments given:

# attempts to notify someone -- False if unsuccessful 
proto notify(Str $userStr $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;
   }
}

Since proto is a wrapper for multi candidates, the signatures of the routine's multi candidates do not necessarily have to match that of the proto; arguments of multi candidates may have subtypes of those of the proto, and the return types of the multi candidates may be entirely different from that of the proto. Using differing types like this is especially useful when giving proto a function body:

enum DebugType <LOG WARNING ERROR>;
 
#|[ Prints a message to stderr with a color-coded key. ] 
proto debug(DebugType:D $typeStr:D $message --> Bool:_{
    note sprintf qb/\e[1;%dm[%s]\e[0m %s/{*}$type.key$message
}
multi debug(LOG;; Str:D --> 32)     { }
multi debug(WARNING;; Str:D --> 33{ }
multi debug(ERROR;; Str:D --> 31)   { }

{*} 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 

A longer example using proto for methods shows how to extract common functionality into a proto method.

class NewClass {
    has $.debug is rw = False;
    has $.value is rw = 'Initial value';
    proto method handle| ) {
        note "before value is 「$.value" if $.debug;
        {*}
        note "after value is 「$.value" if $.debug;
    }
    multi method handle(Str $s{
        $.value = $s;
        say 'in string'
    }
    multi method handle(Positional $s{
        $.value = $s[0];
        say 'in positional'
    }
    multi method handle$a$b ) {
        $.value = "$a is looking askance at $b";
        say 'with more than one value'
    }
}
my NewClass $x .= new;
$x.handle('hello world');
$x.handle(<hello world>);
$x.debug = True;
$x.handle('hello world');
$x.handle(<hello world>);
$x.handle('Claire''John');
# OUTPUT: 
# in string 
# in positional 
# before value is 「hello」 
# in string 
# after value is 「hello world」 
# before value is 「hello world」 
# in positional 
# after value is 「hello」 
# before value is 「hello」 
# with more than one value 
# after value is 「Claire is looking askance at John」