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