Author: autrijus Date: Sat Apr 1 14:01:16 2006 New Revision: 8528 Modified: doc/trunk/design/syn/S06.pod doc/trunk/design/syn/S12.pod doc/trunk/design/syn/S13.pod
Log: * S06+S12: Split the old "multiple-dispatch" into two distinct ideas: - "Method call" vs "Subroutine call" - "Multiple dispatch" vs "Single dispatch" A multi-method or multi-sub is simply a method/sub that has variants, and has nothing to do with transcending class boundaries. <TimToady> With a multi-sub, it's the sub-ness that transcends class boundaries, not the multi-ness. Consequently, $x.foo(3) still falls back to foo($x, 3) if there is not such method, but foo($x, 3) won't magically call the "foo" method even if it's declared as a multi-method. To get the old magical dual behaviour, use "multi submethod". "multi foo" within a class/role now means "multi method foo". Modified: doc/trunk/design/syn/S06.pod ============================================================================== --- doc/trunk/design/syn/S06.pod (original) +++ doc/trunk/design/syn/S06.pod Sat Apr 1 14:01:16 2006 @@ -34,13 +34,6 @@ subroutines masquerading as methods. They have an invocant and belong to a particular kind or class. -B<Multimethods> (keyword: C<multi>) are routines that transcend class -boundaries, and can have one or more invocants. - -B<Prototypes> (keyword: C<proto>) specify the commonalities (such -as parameter names, fixity and associativity) shared by all multis -of that name in the scope of the C<proto> declaration. - B<Rules> (keyword: C<rule>) are methods (of a grammar) that perform pattern matching. Their associated block has a special syntax (see Synopsis 5). @@ -52,6 +45,32 @@ as they are parsed (i.e. at compile-time). Macros may return another source code string or a parse-tree. +=head1 Routine modifiers + +B<Multimethods> (keyword: C<multi>) are routines that can have multiple +variants that shares the same name, selected by arity, types, or some +other constraints. They may have multliple invocants. + +B<Prototypes> (keyword: C<proto>) specify the commonalities (such +as parameter names, fixity and associativity) shared by all multis +of that name in the scope of the C<proto> declaration. + +A modifier keyword may occur before the routine keyword in a named routine: + + proto sub foo {...} + multi sub foo {...} + proto method bar {...} + multi method bar {...} + +If the routine keyword is omitted, it defaults to C<method> inside a +class or role, and C<sub> inside a module or package. + + class C { + multi foo {...} # multi method foo + } + module M { + multi bar {...} # multi sub bar + } =head2 Named subroutines @@ -427,7 +446,7 @@ =head2 Invocant parameters -A method invocant is specified as the first parameter in the parameter +A method invocant may be specified as the first parameter in the parameter list, with a colon (rather than a comma) immediately after it: method get_name ($self:) {...} @@ -442,31 +461,36 @@ Multimethod and multisub invocants are specified at the start of the parameter list, with a colon terminating the list of invocants: - multi sub handle_event ($window, $event: $mode) {...} # two invocants + multi sub handle_event ($window, $event: $mode) {...} # two invocants + multi method set_name ($self, $name: $nick) {...} # two invocants -Multi invocant arguments are passed positionally, though the first -invocant can be passed via the method call syntax if the multi happens -to be defined as a multi method within the class of the first invocant. - - # Multimethod calls... - handle_event($w, $e, $m); - $w.handle_event($e, $m); +If the parameter list for a C<multi> contains no colon to delimit +the list of invocant parameters, then all positional parameters are +considered invocants. If it's a C<multi method> and C<multi submethod>, +an additional implicit unamed C<self> invocant is prepended to the +signature list. + +For the purpose of matching positional arguments against invocant parameters, +the invocant argument passed via the method call syntax is considered the +first positional argument: + + handle_event($w, $e, $m); # calls the multi sub + $w.handle_event($e, $m); # ditto, but only if there is no + # suitable $w.handle_event method Invocants may also be passed using the indirect object syntax, with a colon after them. The colon is just a special form of the comma, and has the same precedence: - # Indirect method call... - set_name $obj: "Sam"; - - # Indirect multimethod call... - handle_event $w, $e: $m; + set_name $obj: "Sam"; # try $obj.set_name("Sam") first, then + # fall-back to set_name($obj, "Sam") + $obj.set_name("Sam"); # same as the above Passing too many or too few invocants is a fatal error if no matching definition can be found. An invocant is the topic of the corresponding method or multi if that -formal parameter is declared with the name C<$_>. A method's single +formal parameter is declared with the name C<$_>. A method's first invocant always has the alias C<self>. Other styles of self can be declared with the C<self> pragma. @@ -726,11 +750,11 @@ =head2 Multidimensional argument list binding -Some functions take multiple Lists that they wish not to be flattened into -one list. For instance, C<zip()> wants to iterate several lists in parallel, -while array and hash subscripts want to process multidimensional slices. -The set of underlying argument list (List) objects may be bound to a single -array parameter declared with a C<;> twigil: +Some functions take multiple C<Arguments> that they wish not to be flattened +into one list. For instance, C<zip()> wants to iterate several lists in +parallel, while array and hash subscripts want to process multidimensional +slices. The set of underlying argument list (List) objects may be bound to a +single array parameter declared with a C<;> twigil: sub foo (*@;slices) { ... } Modified: doc/trunk/design/syn/S12.pod ============================================================================== --- doc/trunk/design/syn/S12.pod (original) +++ doc/trunk/design/syn/S12.pod Sat Apr 1 14:01:16 2006 @@ -174,11 +174,11 @@ my method think (Brain $self: $thought) -(Such methods are completely invisible to the ordinary method dispatch -system, and are in fact called with a different syntax that uses C<!> -in place of the C<.> character. See below.) +(Such methods are completely invisible to ordinary method calls, and are +in fact called with a different syntax that uses C<!> in place of the C<.> +character. See below.) -To call an ordinary method with ordinary single-dispatch semantics, +To call an ordinary method with ordinary method-dispatch semantics, use either the dot notation or indirect object notation: $obj.doit(1,2,3) @@ -195,6 +195,11 @@ close $handle: close $handle +To explicitly reject method call and only consider subs, put a +trailing comma after the single positional argument: + + close($handle,) + Dot notation can omit the invocant if it's in C<$_>: .doit(1,2,3) @@ -574,7 +579,7 @@ $junction.values».meth(@args); -=head1 Multiple dispatch +=head1 Multisubs and Multimethods The "long name" of a subroutine or method includes the type signature of its invocant arguments. The "short name" doesn't. If you put @@ -613,12 +618,12 @@ a final tie-breaking proto sub is called, if there is one (see above). Otherwise an exception is thrown. -Ordinarily all the arguments of a multi sub are considered invocants. +Ordinarily all the parameters of a multi sub are considered invocants. Here's a declaration for an integer range operator with two invocants: multi sub infix:<..>(Int $min, Int $max) {...} -Sometimes you want to have optional arguments that aren't counted +Sometimes you want to have optional parameters that aren't counted as part of the long name. For instance, if you want to allow an optional "step" parameter to your range operator, but not count it as an invocant, put a colon instead of a comma at the end of the @@ -626,49 +631,44 @@ multi sub infix:<..>(Int $min, Int $max: Int $by = 1) {...} -A multi method can be declared within a class, in which case it is -visible to both the single-dispatcher and the multiple-dispatcher. -Such a method's invocants must always be explicitly declared. +Within a class, C<multi submethod> is visible to both method-dispatch +and subroutine-dispatch. A C<multi method> never participates in the +subroutine-dispatch process. -The caller indicates whether to use single dispatch or multiple dispatch +=head2 Method call vs. Subroutine call + +The caller indicates whether to make a method call or subroutine call by the call syntax. The "dot" form and the indirect object form default to -single dispatch. Subroutine calls with multiple arguments and operators -with multiple operands default to multiple dispatch. For functions -or methods with only a single invocant, the dispatchers are defined to have -the same semantics, which is why it doesn't matter which of these you say: +method calls. Calls with multiple arguments and operators with multiple +operands default to subroutine calls. - $handle.close - close($handle) +A function call with a single argument defaults to method calls: -However, with additional arguments, there are differences. The single -dispatch form: + close($handle) + close $handle - $handle.seek($pos) +Use a trailing comma if you want to make a subroutine call instead: -preferentially considers only ordinary methods and multimethods from -the class hierarchy of C<$handle>, and fails over to the multiple -dispatcher as a last resort only if no method can be found in the -class hierarchy. + close($handle,) -On the other hand, the multi dispatch form: +A method call first considers methods (including multi-methods and submethods) +from the class hierarchy of C<$handle>, and fails over to the subroutine +dispatcher as a last resort only if no method can be found in the class +hierarchy. - seek($handle, $pos); +A subroutine call considers only visible subroutines (including submethods) of +that name. There is no fail-over from subroutine to method dispatch. -considers all visible multi subs and multi methods of that -name equally. For this purpose ordinary methods are considered -multi-methods of a single invocant, which, since they are less -specific than the declarations with more invocants, are put at the -end of the list. (So there's no need for an explicit failover from -multiple to single dispatch.) +=head1 Multi dispatch -Multi submethods work just like multi methods except they are constrained +Multi submethods work just like multi subs except they are constrained to an exact type match on the first invocant. Perl 6.0.0 is not required to support multiple dispatch on named parameters, only on positional parameters. Note that most builtins will map known named parameters to positional via a C<proto> declaration. -Within the multiple dispatcher, C<next METHOD> means to try the next best +Within a multiple dispatch, C<next METHOD> means to try the next best match, or next best default in case of tie, or the proto sub if there is one. @@ -686,7 +686,9 @@ The syntax for calling back to C<MyClass> is C<$obj!MyClass::meth()>. -The C<sub> keyword is optional after either C<multi> or C<proto>. +Outside a class or a role, the C<sub> keyword is optional after either +C<multi> or C<proto>. Within a class or a role, the C<method> keyword +is implied instead of C<sub>. A C<proto> declaration must come before any matching multis, if at all. Modified: doc/trunk/design/syn/S13.pod ============================================================================== --- doc/trunk/design/syn/S13.pod (original) +++ doc/trunk/design/syn/S13.pod Sat Apr 1 14:01:16 2006 @@ -63,22 +63,6 @@ multi sub *infix:<~>(Str $s1, ArabicStr $s2) {...} multi sub *infix:<~>(ArabicStr $s1, Str $s2) {...} -Ordinary methods can be turned into multi methods within the class definition: - - class MyNum { - multi method abs(MyNum $x) {...} - ... - } - -Likewise operators on your new type can appear in the class: - - class MyNum { - multi method prefix:<+> (MyNum $x) {...} # what we do in numeric context - multi method prefix:<~> (MyNum $x) {...} # what we do in string context - multi method prefix:<?> (MyNum $x) {...} # what we do in boolean context - ... - } - Binary operators may be declared as commutative: multi sub infix:<+> (Us $us, Them $them) is commutative { myadd($us,$them) }