[Python-Dev] PEP 246, redux

Phillip J. Eby pje at telecommunity.com
Tue Jan 11 20:44:29 CET 2005


At 10:47 AM 1/11/05 -0800, Michael Chermside wrote:
>I'd agree except for the case where I am trying to pass an object
>into code which is misbehaving. If we do add type declarations that
>trigger an adapt() call, then people WILL write poor code which
>declares concrete types, and I will find myself writing __conform__
>methods to work around it. In this case, I'm the one making use of
>adaption (the original author was just expecting a TypeError), but
>what I'm doing isn't (IMO) bad style.

Agreed.  However, assuming that you're declaring a "clean" adaptation, 
perhaps it should be registered with the global registry rather than 
implemented in __conform__, which would be less work for you.


>If we're just recomending that people design for transitivity, then I
>don't have a problem (although see Alex's fairly good point illustrated
>with LotsOfInfo, PersonName, and FullName -- I found it convincing).

It's a bit misleading, however; if the target protocol allows for "nulls", 
then it's allowed to have nulls.  If it doesn't allow nulls, then the 
adaptation is broken.  Either way, it seems to me to work out, you just 
have to decide which way you want it.


>But I was under the impression that the point of transitivity was to
>make it "required", then automatically walk chains of adaptions.

I don't have a problem with making some part of the adaptation process 
avoid transitivity, such as hand-implemented __conform__ methods.


>  Then
>I fear one case of mis-used adaption could "poison" my entire adaption
>mechanism. The N^2 explosion of pairwise-only adapters scares me less,
>because I think in most real situations N will be small.

Well, Eclipse is a pretty good example of a large N, and I know that both 
Twisted and Zope developers have occasionally felt the need to do 
"double-dip" adaptation in order to work around the absence of transitive 
adapter composition in their adaptation systems.


> > If you allow interface inheritance, you're just as susceptible to an
> > invalid adaptation path, and in my experience this is more likely to
> > bite you unintentionally, mainly because interface inheritance works
> > differently than class inheritance (which of course is used more
> > often).  Do you want to prohibit interface inheritance, too?
>
>Hmm. Sounds like you're making a point here that's important, but which
>I don't quite get. Can you elaborate? I certainly hadn't intended to
>prohibit interface inheritance... how exactly does it "bite" one?

If you derive an interface from another interface, this is supposed to mean 
that your derived interface promises to uphold all the promises of the base 
interface.  That is, your derived interface is always usable where the base 
interface is required.

However, oftentimes one mistakenly derives an interface from another while 
meaning that the base interface is *required* by the derived interface, 
which is similar in meaning but subtly different.  Here, you mean to say, 
"IDerived has all of the requirements of IBase", but you have instead said, 
"You can use IDerived wherever IBase is desired".

But now, suppose that you have class Foo, which has an adapter defined to 
IDerived, and which is looked up for you by IDerived.__adapt__ and 
IBase.__adapt__.  Then, if you pass a Foo instance to a function that 
expects an *IBase*, then the function will end up with an IDerived.

Sometimes this is not at all what you want, at which point I normally go 
back and copy the relevant methods from IBase to IDerived and remove the 
inheritance relationship.

This problem exists in Zope's adaptation system as well as in 
PyProtocols.  I have found that I am far less likely to have an adaptation 
problem from defining a questionable adapter, than I am to have one from 
wrongly-used inheritance.  I am now more careful about the inheritance, but 
it's difficult because intuitively an interface defines a *requirement*, so 
it seems logical to inherit from an interface in order to add requirements!

Now, in the case where both an IBase and an IDerived adapter exist, Zope 
and PyProtocols prefer to use the IBase adapter when an IBase is 
requested.  But this doesn't address the problem case, which is where there 
is no IBase-only adaptation.



More information about the Python-Dev mailing list