Larry wrote:

> I would like to point out that for mere mortals, *any* MMD is already too
> complex to be predictable.  

This is the relevant observation here.

This particular mortal's experience is that more than four variants, involving
parameters from more than two hierarchies makes it nearly impossible to
predict all the consequences of MMD.

That's why Class::Multimethods provides coverage and ambiguity-detection
tools, which I expect Perl 6 will need too.

> Regardless of the MMD policy (or range of policies) we allow/enforce,
> I think we need to consider what the naive user is to do in the face
> of the (to them) black box of MMD.  I wonder if there's some way to
> annotate a call to say exactly which routine you expect it to call, and
> then if MMD dispatches elsewhere, you get some kind of a warning that
> tells you exactly why it chose the other routine over your routine.
> It doesn't have to dump the whole MMD decision tree on them, but
> merely say something like "Argument $foo picked a constrained type
> over an unconstrained type".  Or "Argument $bark picked Dog with
> distance 1 over Mammal with distance 2".  Or "Argument $bark picked
> 'Dog where...' with distance 1-ε over Dog with distance 1".

This is exactly the kind of coverage tools I mentioned above. I think it would
suffice to have a module that provides an <is targeting> trait.

> Unless we can feed more specific information to the naive user
> in an easily digestible form, I'm still inclined to say that *any*
> constraint just subtracts "epsilon" from the distance, and if you don't
> write your constraints to be mutually exclusive within a single file,
> and you depend on the dispatch order to distinguish, it's erroneous.

I very strongly support this approach. Perhaps with the elaboration that each
re-specialization subtracts an additional epsilon. So I could distinguish:

        type SingleDigit := Int where [0..9];
        type Three       := SingleDigit where 3;

        multi sub foo(Int n) {...}             #1
        multi sub foo(SingleDigit n) {...}     #2
        multi sub foo(Three n) {...}           #3

        foo(3);     # dispatches to #3 (distance = -2ε)
        foo(4);     # dispatches to #2 (distance = -ε)
        foo(43);    # dispatches to #1 (distance = 0)

> (We could still subtract addtional values of epsilon for later files
> to make Yuval happy--or at least less unhappy...)

This would make Damian very unhappy as it discriminates against good
development practices like refactoring code into modules.

> We could go as far as to make it:
>     Argument $bark picked Dog where... with distance 0.99
>                      over Dog          with distance 1
> Then Yuval's overriding files can be distance 0.98, 0.97, 0.96, etc.
> An epsilon of .01 should be small enough for anyone.  (Or at least
> any engineer.)

Magic numbers are a Really Bad Idea. We managed to avoid them for both
operator precedence and regular MMD. It would be a real shame to introduce
them here.

And I think they're unnecessary. Cumulative infinitesimal epsilons from
cumulative C<where> modifiers does the job just as well, and has the distinct
advantage of not restricting specializations to 99 levels.

> The warner should also detect ambiguities in constraints if we make all
> contraints in a file the same epsilon.  I just showed the warning for
> a single argument, but it should probably tell the distance on all
> the arguments that differ, and maybe even calculate the overall distance
> for them.

Again, Class::Multimethods has prior art for this approach. See the example included in the distribution.


Reply via email to