[Python-3000] Adaptation: T->P vs P->P

Tim Hochberg tim.hochberg at ieee.org
Mon Apr 3 18:14:03 CEST 2006


Nick Coghlan wrote:
[SNIP]
> 
> Tim Hochberg wrote:
> 
>>In this thread, Alex has been advocating adaption where types are 
>>adapted to protocols: T->P adaption for short. By contrast, my two 
>>sample implementations have involved Protocol->Protocol adaption where 
>>objects that implement a certain protocol are adapted to another 
>>protocol: P->P adaption for short. I suppose this also could be 
>>considered T->P->P adaptation since you look up the protocol from the 
>>type, but let's stick with the terminology P->P adaption.
>>
>>Alex has been advocating for adaption for quite a while (I imagine it 
>>seems like forever to him), so I give his views here great weight. 
>>Still, something about T->P adaption has been bothering me, but until 
>>now I haven't been able to put my finger on it beyond a vague sense that 
>>pressing concrete types into service in this way is asking for trouble.
>>
>>Here's the problem I have with T->P adaption: it increases coupling 
>>between the various clients of the adaption process. Lets talk about 
>>these clients, I believe Alex said there were four:
>>
>>1. The author of the type: T
>>2. The writer of the adapter: A
>>3. The person defining the destination protocol: P
>>3. The user of the whole shebang: U
>>
>>Now under a T->P regime, T needs to search out all relevant adapters and 
>>register them for their type. Similarly when adding a new adapter, A 
>>needs to search out all relevant classes and register the new adapter 
>>for them. Thus A and T become highly coupled.
> 
> 
> This misses the whole point of dynamic adaptation.

You dropped this bit of context:

[I realize that I've artificially constrained who registers what, but 
the fact remains that someone has to do the registrations at some point. 
...]

> T and P might define a few 
> convenience adaptations (e.g. to or from standard library interfaces), but A 
> and U will usually be the same person. 

I was simply attempting to copy Alex here. I more or less agree with 
you. Or more precisely, I agree that A will be a U. There may be other 
users that come after that also use A's work. But I'm muddying up the 
jargon here, so I'll stop.

Suppose framework X produces a Wibble,
> and framework Y expects an IWobble in various places. The integrator (U) needs 
> to plug them together. If Wibble provides the right interface, U can simply write:
> 
>    IWobble.register_type(Wibble)
> 
> Or, more commonly, U may need to write an adapter:
> 
>    class WibbleAsIWobble(object):
>        def __init__(self, the_wibble):
>            self.the_wibble = the_wibble
>        # delegate the IWobble API to the Wibble instance
> 
>    IWobble.register_type_adapter(Wibble, WibbleAsIWobble)
> 
> Either way, after either conformance or the adapter have been registered, a 
> Wibble can be used seamlessly anywhere an IWobble was expected.

Suppose instead that the interface of framework X claims that it 
produces a sequence, or a file-like-object or even a WibbleLike object. 
Then U/A needs to dig into the guts of framework X to determine what 
concrete types it actually produces in order to register them for their 
adapter. Then, when A/U downloads the new spiffy version of framework X 
that now can also produce the new WibbleLike object SuperSpiffyWibble, 
things break until A/U figures out what new types can be produced and 
updates things accordingly.

You can work around this if all the WibbleLike objects in framework X 
inherit from some base class WibbleBase (assuming that you are walking 
the MRO), but tying protocols to classes like that is not really the 
python way. And could be a pain in the neck, particularly if some of the 
types involved are implemented in C.

With P->P addaption, the situation is better. The author of framework X 
can simply document that it returns something that satisfies the 
WibbleLike protocol. Then the most that A/U ever needs to do, regardless 
of how many differently implemented Wibbles the frameworks spits out is:

     adaption.register_adapter(WibbleLike, WobbleLike, WibbleAsWobble)

Pep 246 and PyProtocols don't seem to implement either P->P or T->P 
adaption. That's because the __conform__ method can do pretty much 
anything it wants -- the other portions of PEP 246 appear to be pretty 
much vanilla T->P. In a sense, P->P adaption is an attempt to come 
closer to the power of PEP 246 without the complexity of the arcane 
identity/conform/adapt/registry dance.

Zope adapation appears to be P->P, although it can also do T->P. In 
general, it should be trivial to have a P->P setup also do T->P adaption.


Regards,

-tim



More information about the Python-3000 mailing list