[Python-Dev] PEP 246, redux

Clark C. Evans cce at clarkevans.com
Thu Jan 13 19:21:42 CET 2005


On Thu, Jan 13, 2005 at 06:27:08PM +0100, Alex Martelli wrote:
| >The 'implicit' adaptation refers to the automagical construction of
| >composite adapters assuming that a 'transitive' property holds. I've
| >seen nothing in this thread to explain why this is so valueable, why
| 
| Let me play devil's advocate: I _have_ seen explanations of why 
| transitive adaptation can be convenient -- the most direct one being an 
| example by Guido which came in two parts, the second one a 
| clarification which came in response to my request about the first one. 

hypothetical pseudocode ;)

| To summarize it: say we have N concrete classes A1, A2, ... AN which 
| all implement interface I.
| Now we want to integrate into the system function f1, which requires an 
| argument with interface J1, i.e.
|     def f1(x):
|         x = adapt(x, J1)
|         ...
| or in Guido's new notation equivalently
|     def f1(x: J1):
|         ...
| and also f2, ..., fM, requiring an argument with interface J2, ..., JM 
| respectively.
| 
| Without transitivity, we need to code and register M*N adapters. 

Are you _sure_ you have M*N adapters here?  But even so,

  for j in (J1,J2,J3,J4,...,JM)
    for i in (I1,I2,...,IN):
      register(j,i)

| WITH transitivity, we only need M: I->J1, I->J2, ..., I->JM.

Without transitivity, a given programmer, in a given module will
probably only use a few of these permutations; and in each case,
you can argue that the developer should be aware of the 'automatic'
conversions that are going on.  Imagine an application developer
plugging a component into a framework and getting this error:

    """Adaption Error
   
    Could not convert A1 to a J1.   There are two adaption pathways
    which you could register to do this conversion for you:
   
    # A1->I1 followed by I1->J1
    adapt.registerPath((A1,I1),(I1,J1))
    
    # A1->X3 followed by X3 -> PQ follwed by PQ -> J1
    adapt.registerPath((A1,X3),(X3,PQ),(PQ,J1))
    """

The other issue with registries (and why I avoided them in the origional
PEP) is that they often require a scoping; in this case, the path taken
by one module might be different from the one needed by another.

| The convenience of this is undeniable; and (all other things being 
| equal) convenience raises productivity and thus is valuable.

It also hides assumptions.  If you are doing adaptation paths

| James Knight gave a real-life example, although, since no combinatorial 
| explosion was involved, the extra convenience that he missed in 
| transitivity was minor compared to the potential for it when the N*M 
| issue should arise.

Right.  And that's more like it.

| >it shouldn't be explicit,
| 
| On this point I'm partly with you: I do not see any real loss of 
| convenience in requiring that an adapter which is so perfect and 
| lossless as to be usable in transitivity chains be explicitly so 
| registered/defined/marker.  E.g., provide a
|     registerAdapter_TRANSITIVITY_SUITABLE(X, Y)
| entry in addition to the standard registerAdapter which does not supply 
| transitivity (or equivalently an optional suitable_for_transitivity 
| argument to registerAdapter defaulting to False, etc, etc).

Ok.  I just think you all are solving a problem that doesn't exist,
and in the process hurting a the more common use case:

   A component developer X and a framework developer Y both 
   have stuff that an application developer A is putting
   together.  The goal is for A to not worry about _how_ the
   components and the framework fit; to automatically "find"
   the glue code.

The assertion that you can layer glue... is well, tenuous at best.

| In terms of "should" as opposed to convenience, though, the argument is 
| that interface to interface adapters SHOULD always, inherently be 
| suitable for transitive chains because there is NO reason, EVER, under 
| ANY circumstances, to have such adapters be less than perfect, 
| lossless, noiseless, etc, etc. 

I strongly disagree; the most useful adapters are the ones that
discard unneeded information.  The big picture above, where you're
plugging components into the framework will in most cases be lossy
-- or the frameworks / components would be identical and you woudn't
want to hook them up. Frankly, I think the whole idea of "perfect
adapters" is just, well, arrogant.  

| > and on the contrary, most of the "problems
| >with adapt()" seem to stem from this aggressive extension of what
| >was proposed: Automatic construction of adapter chains is _not_ part
| 
| Fair enough, except that it's not just chains of explicitly registered 
| adapters: interface inheritance has just the same issues, indeed, in 
| PJE's experience, MORE so, because no code is interposed -- if by 
| inheriting an interface you're asserting 100% no-problem 
| substitutability, the resulting "transitivity" may thus well give 
| problems (PJE and I even came close to agreeing that MS COM's 
| QueryInterface idea that interface inheritance does NOT implicitly and 
| undeniably assert substitutability is very practical, nice, and 
| usable...).
| 
| >of the original PEP 246 and I hope it remains that way.   I've
| >outlined in several posts how this case could be made easy for a
| >application developer to do:
| >
| >  - transitive adapters should always be explicit
| 
| What about "registered explicitly as being suitable for transitivity", 
| would that suffice?

I suppose so.  But I think it is a bad idea for a few reasons:

  1. it seems to add complexity without a real-world justifcation,
     let's go without it; and add it in a later version if it turns
     out to be as valueable as people think
     
  2. different adapters have different intents, and I think a given
     adapter may be perfect in one situation, it may royally 
     screw up in another; users of systems often break interfaces
     to meet immediate needs.  In your strawman I can think of
     several such twists-and-turns that an "obviously perfect"
     adapter would fail to handle:
     
       - In the 'structure' variety (where the middle name is
         not necessarly placed in the middle), someone decides
         to store one's title... beacuse, well, the slot is
         there and they need to store this information
         
       - In the 'ordered' variety, "John P. Smith", you might
         have "Murata Makoto".  If you thought Makoto was the
         last name... you'd be wrong.
        
In short, unless a human is giving the 'ok' to an adapter's
use, be it the application, framework, or component developer,
then I'd expect wacko bugs.

| >The 'registry' idea (which was not explored in the PEP) emerges from
| >the need, albeit limited, for the application developer who is
| >plugging a component into a framework, to have some say in the
| >process.  I think that any actions taken by the user, by registering
| >an adapter, should be explicit.
| 
| Jim Fulton is VERY keen to have registration of adapters happen "behind 
| the scenes" at startup, starting from some kind of declarative form (a 
| configuration textfile or the like), given the deployment needs of 
| Zope3 -- that shouldn't be a problem, it seems to me (if we have a way 
| to to explicit registrations, zope3 can have a startup component that 
| finds configuration files and does the registration calls based on that 
| 'declarative' form).

That's fine.  

| This potentially opens the door to N-players scenarios for N>3, but, 
| like going from 3-tier to N-tier applications, that's not as huge a 
| jump as that from N==2 to N==3;-).

The problem with registries is that often times scope is needed;
just beacuse my module wants to use this adaption path, doesn't 
mean your module will make the same choice.  I avoided registries
in the first pass of the draft to avoid this issue.  So, if we
are going to add registries, then namespaces for the registries
need to also be discussed.

| So, are you willing to do that round of editing to PEP 246...?  I'll 
| then to the NEXT one which will still undoubtedly be needed...

I could make a wack at it this weekend.

Best,

clark



More information about the Python-Dev mailing list