[Python-Dev] Re: Multimethods (quelle horreur?)
David Abrahams
David Abrahams" <dave@boost-consulting.com
Sat, 17 Aug 2002 17:57:39 -0400
From: "Samuele Pedroni" <pedroni@inf.ethz.ch>
> the question was whether
> adding a method to a gf
> is always the moral equivalent of
>
> lib.py:
>
> class A:
> def meth(self,...): ...
>
> class B(A): ...
>
> class C(B):
> def meth(self,...): ...
>
> abusive_user.py:
>
> from lib import A
>
> def foo(...): ...
>
> A.meth=foo
And the answer is, "clearly not always".
> > Well, I still don't get it. I clearly don't know what "fiddling"
means,
> > since any added signature can change the behavior of the multimethod. I
> > think I would be inclined to forbid your first case, where you're
adding a
> > multimethod implementation whose signature exactly matches another one
> > > that's already in the multimethod.
>
> The point is whether the behavior is changed in an undetected way
> with respect to sets of arguments for which some matching signature/
> method is already defined. So my conditions
>
> add(M,(h,T3)) with T3==T2 (*) or T1<T3<T2.
> (assuming that T3==T2 triggers substitution) .
>
> [T3==T2 case corresponds to the above
>
> A.meth = foo
I hope you are covering this case just for generality's sake. It's easy
enough to forbid.
> T1<T3<T2 correspond to the single dispatch case:
>
> from lib import B
>
> B.meth=... ]
I don't understand why you're using such a complicated condition; you can
change the behavior "in an undetected way WRT sets of arguments for which
some matching signature/method is already defined" simply by adding a
signature T4 s.t. T4 < X for some X in the signatures of the multimethod.
> If T3 is < or uncomparable with all the signatures
> already in M:
> - you are doing the moral equivalent of overriding
> in the single dispatch case
Sort of. You might not be the same person that supplies the types in T3.
> - or you are defining the gf for some unrelated
> class hierarchies
Yep.
> - or some case that was unambiguous
> will become ambiguous and the outcome
> will depend on the rules you choose to
> deal with ambiguity (which is a general
> problem with multidispatching).
Yep.
> > > [Btw up to (*), missing a module or calling
> > > a generic function before all modules are loaded,
> > > load order does not count.]
> > The above sentence is completely incomprehensible to me.
>
> Dispatching outcomes are invariant wrt
> the order by which you add gf-methods to a gf.
It depends on your dispatching rules, of course. However, I'd like to pick
order-independent rules.
> > > See my posted code for the idea of redispatching
> > > on forced types, which seems to me reasonably Pythonic
> > > and allows OTOH to choose a very strict approach
> > > in face of ambiguity because there's anyway a user
> > > controllable escape.
> >
> > Could you please explain your scheme in plain English?
> > What is a "forced type"?
>
> the idea is to allow optionally to specify together
> with an argument a supertype of the argument and to have
> the dispatching mechanism use the supertype instead
> of the type of the argument for dispatching:
>
> gf(a,b,_redispatch=(None,SuperTypeOf_b))
>
> the dispatch mechanism will consider the
> tuple (type(a),SuperTypeOf_b) instead
> of (type(a),type(b)) for dispatching.
More "sugarily:"
gf(a, dispatch_as(b, SuperTypeOf_b))
Interesting. Not sure how I feel about this.
> This is the moral equivalent of
> single dispatching:
>
> SuperTypeOf_b.meth(b)
>
> or super(SuperTypeOf_b).meth(b)
Hmm. OK, I see the analogy. I hardly ever have to do that even in the
single case, but I get what you're up to.
> > > My opinion: left-to-right and refuse ambiguity
> > > are depending on the generic function both
> > > reasonable approaches.
>
> > I assume that "left-to-right" is some kind of precedence ordering for
> > ambiguous multimethod implementations. Can you give an example where
that
> > would be appropriate?
>
> is the default used by CLOS, that simply means that
> signature (type tuples) are compared using the lexico-order,
>
> given
> class A: pass
> class B(A): pass
>
> then (B,A)<(A,B)
>
> you get the same effect as multidispatching
> simulated through chained single dispatching.
That seems a bit arbitrary, but I guess there are other precedents in
Python for an arbitrary ordering (e.g. ordering on type names for
heterogeneous object comparison).
> > > The proposed notation or whatever should be at most
> > > just syntax sugar:
> > >
> > > (a,b,c).f(d) === f(a,b,c,d) in general.
> >
> > All notations (except really ugly ones) are syntax sugar. What point
are
> > you trying to make?
>
> what I was trying to convoy is that it would
> be bad to have multimethod invocation be a special
> operation different from the usual function invocation
> (which currently is at work also for method invocation).
Agreed.
> > It now looks like you were trying to say in 3. that multimethods
should be
> > invokable and definable in the same way as single-methods.
>
> no, I was saying that at most
>
> (a,).gf(b) should just be equivalent to gf(a,b) (*)
>
> but plain a.meth() should still mean what it means today.
>
> But honestly I find (*) unnecessary and ugly.
> I'm not even sure one can really disambiguate
> such syntax:
>
> (a,b).__contains__(2)
> (a,).__contains__(2)
>
> are valid Python.
>
> >Well, I'm not
> > sure that this elegant idea from Dylan is essential or even
neccessarily
> > good for Python. It's cute, but what does it really buy us?
>
> nothing. My point is that once we have multimethods,
> one has the choice, one can
> define classes without normal methods and just use multimethods instead,
There's the (minor?) issue of access to "private" members whose names begin
with two underscores.
> I was not advocating that C().meth() should be equivalent
> to meth(C()) in every respect and that the method definitions
> inside the class definitions should triggers gf-method
> definitions. It would be a disruptive change for Python.
>
> So we agree.
Good!
> Multidispatching functions should be an extension of the notion
> of function in Python not of class methods. OTOH
> class methods are defined by defining functions
> inside class namespaces, so it should be possible
> to get class methods also from gfs defined
> in a class namespace.
Yes, I strongly agree.
-Dave