[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