[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