Multiple dispatch again

Samuele Pedroni pedronis at bluewin.ch
Fri Jan 3 15:26:37 CET 2003


"David Mertz" <mertz at gnosis.cx> ha scritto nel messaggio
news:mailman.1041585365.7351.python-list at python.org...
> "Samuele Pedroni" <pedronis at bluewin.ch> wrote previously:
> |Unless you have only single inheritance and so you don't need
> |linearization of class hierarchies, I don't think the weighted
> |approach is manageable.
>
> Well...  I think Damian Conway is pretty smart guy.  And the weighted
> approach is what he did in his Perl version.  I'm not necessarily in
> favor of that linearization over others, but I don't see anything
> obviously wrong about it.

Damian Conway on his method:

"some languages (e.g. CLOS) take a different approach -- breaking the tie by
a recount on the inheritance distance of each argument starting from the
left. In this example, that would mean that the call would be dispatched to
put_peg(RoundPeg,Hole), since the left-most parameter of that variant is a
``closer'' match than the left-most parameter of the put_peg(Peg,SquareHole)
variant.

In the author's opinion, this approach is appalling, since it favours one
parameter above all others for no better reason than it comes first in the
argument list. But there is no reason why pegs should be more significant
than holes. Moreover, arbitrarily resolving the dispatch in this way will
often mask a fundamental design flaw in the multimethod."

If those are the worries then I would go the Dylan route: the applicable
methods' signatures should be all comparable given the class precedence list
of the arguments otherwise the dispatch is ambiguous.

This avoids masked flaws and avoid guessing. This is an ideal for something
like an arithmetic operator, figure intersection etc

In practice sometimes choosing to break ties using some order on the
arguments can be useful, what one gets is like chaining single inheritance
dispatch. Also in this case it is not hard to have a grasp on what will
happen.

So I think that a multi method dispatch mechanism should provide support for
both approaches.

About the weighted approach:
- Python uses linearization (the mro) for single dispatch, your
implementation uses that to compute the "inheritance distance", and I don't
know what Perl counterpart does
- "inheritance distance" in the presence of multiple inheritance is for sure
a tricky thing to get right and manageable.

the problem is that it is hard to have a firm grasp on dispatching and the
results can feel rather arbitrary,  consider

class A(object): pass
class B(A): pass
class C(B): pass

the signatures

(A,B)
(B,A)

are ambiguous for Dylan no matter what, now with the weighted approach if we
dispatch on (C,C) for example
[I'm using a modified version of weighted_mro that returns matches]

>>> m=[[(A,B),None,None],[(B,A),None,None]]
>>> scratch.weighted_mro((C,C),m)
[(3, [(<class '__main__.A'>, <class '__main__.B'>), None, None]), (3,
[(<class '__main__.B'>, <class '__main__.A'>), None, None])]

they are ambiguous.

Now:

class D(A): pass
class E(C,D): pass

(E's mro (C3 or 2.2) is E,C,B,D,A,object )

>>> m=[[(A,B),None,None],[(B,A),None,None]]
>>> scratch.weighted_mro((C,E),m)
[(4, [(<class '__main__.A'>, <class '__main__.B'>), None, None]), (5,
[(<class '__main__.B'>, <class '__main__.A'>), None, None])]

go figure.

regards.






More information about the Python-list mailing list