Here is a zeroth-draft description of the new MMD algorithm for S06.


Multi(sub/method) Dispatch

A multi is a set of variants.  Each variant is a Code, with its own
Signature.  A normal call to a multi is handled by the variant whose
signature most tightly matches the call's arguments.  If no variant is
the unambiguous best fit, an error is raised.

Variants may have arbitrarily different signatures.  The first step in
dispatch is to check for compatibility with the call's arguments.  Any
variant whose signature is incompatible with the call is ignored.  The
second and final step is to choose among the compatible variants.
Named parameters, while checked for compatibility, do not currently
affect choice.

Positional parameters can be separated by commas, semicolons, or a
double semicolon (which may appear at most once, after all
semicolons).  Parameters separated by commas are "equally important".
Parameters after a semicolon are "of secondary importance" compared to
those before it.  Parameters after a double semicolon are
"unimportant", incidental to choice.

All compatible variants begin the choice process as "qualified" to be
chosen, and "voting" (able to disqualify other variants).  Each
variant keeps its own score card of who is qualified and who is
voting.  Initially everyone agrees, but as semicolons are encountered,
world views may diverge.

The choice process examines each parameter position individually, from
left to right.  Parameter types are compared for type narrowness.  A
qualified variant whose parameter type is not at least as narrow as
that of each voting variant is disqualified. So unambiguous best fit is
a sudden death competition.  But different variants may have different
views of which variants are still qualified and voting.  So the choice
process broadcasts "everyone who still believes variant x is voting,
should now mark variant y as disqualified".

When a variant encounters a double semicolon in its own signature, it
tells everyone to mark it non-voting.  Its following parameters are
"unimportant", so it doesn't want anyone disqualified by them.

When a variant encounters a single semicolon in its own signature, all
non-qualified variants on its own score card, only, are marked as also
non-voting.  The following parameters are "of secondary importance",
so it doesn't care about conflicts with variants which have already
been disqualified, by the strictly more important preceding
parameters.  This is the "No!  I'm NOT disqualified!  Their vote
doesn't matter!"  rule.

After all the positions are processed, if all variants consider a
single unique variant to be qualified, it is chosen.  Otherwise an
ambiguity error is raised.

Semicolons reduce the frequency of ambiguity.  The unambiguous best
fit policy, with its sudden death "if any parameter type isn't at
least as narrow as that of the competition, just once, anywhere, then
you are not qualified to be chosen", tends to disqualify everyone.
Single semicolons provide a way of saying "variants already
disqualified on the left, are now ineligible to disqualify ME on the
right".  But different variants may have semicolons in different
places.  So the requirement is every variant's vision of importance
must yield the same result.

Parameter types are compared by their relative type narrowness.  If
implicit type conversions were needed on the type compatibility path
between a parameter type and the argument type, then the parameter
with the fewest such conversions is narrower, and we are done.  If a
parameter type is all roles, then class Any is added.  Then we
recursively add all roles, superclasses, and subtypes.  All
anonymous subtypes ("where" clauses) are considered distinct.  We
now have the full set of the type constraints, which are all
conceptually predicates, implied by a parameter's type.  If one set is
a superset of the other, it is narrower (more constraints listed).
Identical sets are equivalent.

If neither is a superset, then we check if their differences consist entirely
of roles.  If so, they are considered equivalently narrow.  (This is so roles
listed in the parameter types, but not associated with a listed class, are
still comparable.)  Otherwise, the parameter types are incomparable: Neither
can then be contenders, because we can't say that either one is at least as
narrow as the other.

Union types types such as (Dog|Cat) is considered comparable to Dog and Cat,
but both Dog and Cat are more specific than (Dog|Cat).  That is, "Dog" can
imply (Dog|Cat), but not the other way around.  However, if "Dog" is a subset
of "Cat", then (Dog|Cat) is first flattened to "Cat" before comparison.

== Handling Optional and Slurpy Parameters

Optional parameters need special consideration, because they represent two
options themselves: one with with the argument and one without.  Slurpy
parameters have the same concern, as they can take zero or more arguments
themselves.  For each optional parameter, a case with and without the optional
parameter is considered.

Examples: 

   Arguments (a => 'b') to signatures 1. () and 2. (*%h) calls 2
   Arguments (<1 2 3>) to signatures 1. () and 2. (@a?) calls 2
   Arguments (@a) to signatures 1. (@a?) and 2. (@a) IS TIE

Note that the variant /with/ the parameter can be considered an exact match, but
but the variant /without/ it cannot be considered an exact match. That rule 
makes the following example work:

   Arguments () to signatures 1. (@a?) and 2. () calls 2

------------------------------------------------------------
Backstory and discussion:


nothingmuch rants on named params:

I think that named arguments could work quite easily if they are treated as
unordered (no left to right ordering - make it completely symmetrical (and
sadly more ambiguous)) between instances of semicolons.

Additionally (this may be crazy), if there is a lexical ordering in the caller
(and *ONLY* lexical ordering, e.g. f( x => 1, y => 2 ), and *NOT*
f([,] %args)), the order may be used for tie breaking.

Another idea is that instead of making non voting a boolean, it's a counter,
that is decremented. In this scenario you have multiple levels of things, and
you could splice up named arguments into more finely grained priority groups.




nothingmuch rants disambiguation strategies:

1. explicitly state variant using fully qualified addressing (symbol entry, and
   variant address within multi - either by index, or by name -- must be able to
   give variants "inner" names)

2. annotate "important" roles/types in your given args (partial or full
   signature in caller): f( Storable x => $x ); # more important than another role

# vim ft:text
