[Python-Dev] PEP 246, redux

Phillip J. Eby pje at telecommunity.com
Tue Jan 11 19:32:53 CET 2005


At 11:59 AM 1/11/05 +0100, Alex Martelli wrote:
>On 2005 Jan 11, at 11:01, Alex Martelli wrote:
>>On 2005 Jan 10, at 18:59, Phillip J. Eby wrote:
>>>At 12:43 PM 1/10/05 -0500, Phillip J. Eby wrote:
>>>>As a practical matter, all of the existing interface systems (Zope, 
>>>>PyProtocols, and even the defunct Twisted implementation) treat 
>>>>interface inheritance as guaranteeing substitutability for the base 
>>>>interface, and do so transitively.
>>>
>>>An additional data point, by the way: the Eclipse Java IDE has an 
>>>adaptation system that works very much like PEP 246 does, and it appears 
>>>that in a future release they intend to support automatic adapter 
>>>transitivity, so as to avoid requiring each provider of an interface to 
>>>"provide O(n^2) adapters when writing the nth version of an 
>>>interface."  IOW, their current release is transitive only for interface 
>>>inheritance ala Zope or Twisted; their future release will be transitive 
>>>for adapter chains ala PyProtocols.
>>
>>This is definitely relevant prior art, so thanks for pointing it out.
>>If interfaces change so often that 'n' can become worryingly high, this 
>>is a valid concern.  In my world, though, published interfaces do NOT 
>>change as often as to require such remedies;-).

FWIW, I don't believe that by "nth version" the original author wasn't 
referring to changed versions of the same interface, but was instead maybe 
trying to say that N interfaces that adapt to IFoo, when IFoo has M 
interfaces that it can be adapted to, means that N*M adapters are required 
in all, if adapter composition isn't possible.


>"adapters" for a single underlying "object", is, I fear, stronger than we 
>can impose (so it may be that Eclipse is a better parallel, but I know 
>little of it while COM is in my bones, so that's what I keep thinking of;-).

Fair enough.  I think Eclipse's *implementation* maps fairly directly onto 
PEP 246, except that __conform__ is replaced by a 'getAdapter()' method, 
and an AdapterManager is used to look up adapters in place of both 
__adapt__ and the PEP 246 registry.  So, it is much closer to PEP 246 than 
COM, in that COM all adaptation is managed by the object, and it cannot be 
externally adapted.  (At least, the last I looked at COM many years ago it 
was the case; maybe that has changed now?)


>So, I see transitivity as a nice thing to have _IF_ it's something that 
>gets explicitly asserted for a certain adapter -- if the adapter has to 
>explicitly state to the system that it "isn't lossy" (maybe), or "isn't 
>noisy" (perhaps more useful), or something like that... some amount of 
>reassurance about the adapter that makes it fully safe to use in such a chain.

Maybe, although I think in our other thread we may be converging on 
definitions of lossy and noisy that are such we can agree that it's not 
really a problem.  (I hope.)


>Maybe it might suffice to let an adapter which IS 'lossy' (or, more 
>likely, one that is 'noisy') state the fact.

I don't see a valid use case for implementing such a thing as an 
automatically-invoked adapter.


>   I'm always reluctant by instinct to default to convenient but risky 
> behavior, trusting programmers to explicitly assert otherwise when 
> needed; but in many ways this kind of design is a part of Python and 
> works fine (_with_ the BDFL's fine nose/instinct for making the right 
> compromise between convenience and safety in each case, of course).

Proposal: let adaptation implemented via __conform__ be nontransitive, and 
adaptation via __adapt__ or the adapter registry be transitive.

This would mean that lossy or noisy adapters could be implemented as an 
implicitly-executed explicit conversion, but only directly on a particular 
concrete class and its subclasses, thereby further limiting the scope and 
impact of a lossy or noisy adapter.

Also, think about this: technically, if you implement lossy or noisy 
adaptation in __conform__, it *isn't* lossy or noisy, because you have to 
do it in the class -- which means that as the class' author, you have 
decreed it to have such semantics.  However, if you are a third party, you 
will have to explicitly invoke the lossy or noisy adapter.

IOW, if you globally register an adapter (with either the interface or the 
global registry), you are guaranteeing that your adaptation is not lossy or 
noisy.  Otherwise, you need to put it in __conform__ or use it explicitly.


>I'm still pondering the "don't adapt an adapter" suggestion, which seems a 
>sound one, and yet also seems to be, intrinsically, what 
>transitivity-by-chaining does.  Note that QI does not suffer from this, 
>because it lets you get the underlying object identity (IUnknown) from any 
>interface adapter.  Maybe, just maybe, we should also consider that -- a 
>distinguished protocol bereft of any real substance but acting as a flag 
>for "real unadapted object identity".  Perhaps we could use 'object' for 
>that, at least if the flow of logic in 'adapt' stays as in the current PEP 
>246 draft (i.e., __conform__ is given a chance before isinstance triggers 
>-- so, all adapters could __conform__ to object by returning the 
>underlying object being adapted, while other objects without such a 
>feature in __conform__ would end up with 'adapt(x, object) is x').  Or, if 
>object in this role turns out to be confusing, IDentity (;-) or some other 
>specially designed protocol.

It's a nice idea; the only problem I see is how far down it goes.  Any 
adapter composition implies that adapters need to know whether to also call 
adapt(x,object) on their adaptee.



More information about the Python-Dev mailing list