Skip to content

Commit

Permalink
documenting when order-of-declaration matters with multi-dispatch (Fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
doomvox authored and JJ committed Oct 9, 2021
1 parent a354a2d commit 2a2ac73
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 9 deletions.
79 changes: 75 additions & 4 deletions doc/Language/functions.pod6
Original file line number Diff line number Diff line change
Expand Up @@ -270,8 +270,9 @@ signatures. When the routine is called by name, the runtime environment
determines the proper I<candidate> and invokes it.
Each candidate is declared with the C<multi> keyword. Dispatch happens
depending on the number (L<arity|/type/Code#method_arity>), type
and name of arguments. Consider the following example:
depending on the number (L<arity|/type/Code#method_arity>); type
and name of arguments; and under some circumstances the order of the
multi definitions. Consider the following example:
=begin code
# version 1
Expand Down Expand Up @@ -345,7 +346,9 @@ for the L<Signature|/type/Signature#Type_constraints> class.
say as-json( 10.3 ); # OUTPUT: «10.3␤»
say as-json( [ True, 10.3, False, 24 ] ); # OUTPUT: «[true, 10.3, false, 24]␤»
For some signature differences (notably when using a where clause or a subset)
the order of definition of the multi methods or subs is used, evaluating
each possibility in turn. See L<multi resolution by order of definition> below for examples.
C<multi> without any specific routine type always defaults to a C<sub>, but you
can use it on methods as well. The candidates are all the multi methods of the
Expand Down Expand Up @@ -509,7 +512,7 @@ $x.handle('Claire', 'John');
# with more than one value
# after value is 「Claire is looking askance at John」
=head2 X<only|declarator>
=head3 X<only|declarator>
The C<only> keyword preceding C<sub> or C<method> indicates that it will be the
only function with that name that inhabits a given namespace.
Expand Down Expand Up @@ -540,6 +543,74 @@ at /tmp/only-redeclaration.p6:3
Anonymous sub cannot be declared C<only>. C<only sub {}> will throw an error of
type, surprisingly, C<X::Anon::Multi>.
=head3 multi resolution by order of definition
When the breakdown by parameter type is not enough to find an unamiguous
match, there are some different tie breakers that may be evaluated in order
of declaration of the methods or subs: these include where clauses and
subsets, named parameters, and signature unpacks.
In this code example, two multi subs are distinguished only by where clauses
where there's one ambiguous case that might pass either of them, the value 4.
In this case, which ever multi sub is defined first wins:
=begin code
{
multi sub check_range ( Int $n where {$_ > 3} ) {
return "over 3";
};
multi sub check_range ( Int $n where {$_ < 5} ) {
return "under 5";
};
say check_range(4); # OUTPUT: over 3
}
{
multi sub check_range ( Int $n where {$_ < 5} ) {
return "under 5";
};
multi sub check_range ( Int $n where {$_ > 3} ) {
return "over 3";
};
say check_range(4); # OUTPUT: under 5
}
=end code
In the following example, three subsets are used to restrict strings to
certain allowed values, where there are overlaps between all three:
=begin code
subset Monster of Str where { $_ eq any( <godzilla gammera ghidora> ) };
subset Hero of Str where { $_ eq any( <godzilla ultraman inframan> ) };
subset Knockoff of Str where { $_ eq any( <gammera inframan thorndike> ) };
{
multi sub speak (Monster $name) {
say "The monster, $name roars!";
}
multi sub speak (Hero $name) {
say "The hero, $name shouts!";
}
multi sub speak (Knockoff $name) {
say "The knockoff, $name, slinks away...";
}
speak('godzilla'); # OUTPUT: The monster, godzilla roars!
speak('gammera'); # OUTPUT: The monster, gammera roars!
speak('inframan'); # OUTPUT: The hero, inframan shouts!
}
=end code
Note that here 'godzilla' is treated as Monster, not as Hero, because the
Monster multi comes first; and neither 'gammera' or 'inframan' are treated
as Knockoff, because that multi comes last.
It should be noted that the order of definition is the order in which Raku
sees them, which might not be easy to discern if, for example, the multi
subs were imported from different modules. As the organization of a code
base becomes more complex, object classes may scale better than using
subsets as types, as in this example.
=head1 Conventions and idioms
While the dispatch system described above provides a lot of flexibility,
Expand Down
19 changes: 14 additions & 5 deletions doc/Language/glossary.pod6
Original file line number Diff line number Diff line change
Expand Up @@ -730,11 +730,20 @@ X<|Multi-Dispatch>
X<|MMD>
=head1 Multi-dispatch
The process of picking a candidate for calling of a set
of L<methods|/type/Method> or L<subs|/type/Sub> that
come by the same name but with different arguments. The most narrow
candidate wins. In case of an ambiguity, a routine with C<is default> trait
will be chosen if one exists, otherwise an exception is thrown.
The mechanism used to invoke different routines (L<methods|/type/Method> or
L<subs|/type/Sub>) of the same name, selecting the correct one based on the
L<parameter|/type/Parameter> prototype and the arguments it was called with.
The selection process is primarily based on types and number of arguments
(L<arity|/type/Arity>), where the narrowest, most specific candidate wins,
typically without regard to the order of declaration. The C<is default>
trait may be used as a tie breaker in this first phase. There is also a
secondary phase where some different tie breakers may be evaluated in order
of declaration of the methods or subs: these include where clauses and
subsets based on them, named parameters, and signature unpacks.
An exception is thrown if this process fails and there's no unambiguous
winning candidate.
X<|multi-method>
=head1 multi-method
Expand Down

0 comments on commit 2a2ac73

Please sign in to comment.