[Python-Dev] PEP 246, redux

Clark C. Evans cce at clarkevans.com
Thu Jan 13 15:34:21 CET 2005


On Thu, Jan 13, 2005 at 10:35:39AM +0000, Paul Moore wrote:
| One thing I feel is key is the fact that adaptation is a *tool*, and
| as such will be used in different ways by different people. That is
| not a bad thing, even if it does mean that some people will abuse the tool.
| 
| Now, a lot of the talk has referred to "implicit" adaptation. I'm
| still struggling to understand how that concept applies in practice,
| beyond the case of adaptation chains - at some level, all adaptation
| is "explicit", insofar as it is triggered by an adapt() call.

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
it shouldn't be explicit, 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
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
  - it should be an error to have more than one adapter 
    from A to Z in the registry
  - when adaptation fails, an informative error message can
    tell the application developer of possible "chains" 
    which could work
  - registration of transitive adapters can be simple command
    application developers use:  adapt.transitive(from=A,to=Z,via=M)
    error message can tell an application developer 

| James Knight's example (which seemed to get lost in the discussion, or
| at least no-one commented on it) brought up a new point for me, namely
| the fact that it's the library writer who creates interfaces, and
| calls adapt(), but it's the library *user* who says what classes
| support (can be adapted to) what interface. I hadn't focused on the
| different people involved before this point.

I'd say the more common pattern is three players.  The framework
builder, the component budiler, and the application designer.  Adapt
provides a mechansim for the framework builder (via __adapt__) and
the component builder (via __conform__) to work together without
involving the application designer.

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.  

The 'diamond' problem discussed by Phillip has only confirmed this
belief.  You don't want the adapt() system going around assuming
transitivity.  However, if the application developer is certain that
a conversion path from A to Z going through B, and/or Y will work,
then it should be easy for them to specify this adaptation path.

| Now, if we have a transitive case A->B->C, where A is written by "the
| user", and C is part of "the library" and library code calls
| adapt(x,C) where x is a variable which the user supplies as an object
| of type A, then WHO IS RESPONSIBLE FOR B???? And does it matter, and
| if it does, then what are the differences?

Great question.  But I'd like to rephrase that C is probably a framework,
A and B are probably components; and we assume that either the framework
or component developers have enabled A->B and B->C.   If the user wishes
to make an adapter from A->C assuming no (or acceptable for his purposes)
information loss from A->C through B, then this is his/her choice.  However,
it shouldn't be done by the framework or component developers unless it is
a perfect adaptation, and it certainly shouldn't be automagic.

I don't think who owns B is particularly more important than A or C.

| As I write this, being careful *not* to talk interms of "interfaces"
| and "classes", I start to see Philip's point - in my mind, A (written
| by the user) is a class, and C (part of the library) is an
| "interface". So the answer to the question above about B is that it
| depends on whether B is an interface or a class - and the sensible
| transitivity rules could easily (I don't have the experience to
| decide) depend on whether B is a class or an interface.

I'd like to say that _any_ transitivity rule should be explicit; there
is a point where you make it easy for the programmer, but for heavens
sake, let's not try to do their job.

| BUT, and again, Philip has made this point, I can't reason about
| interfaces in the context of PEP 246, because interfaces aren't
| defined there. So PEP 246 can't make a clear statement about
| transitivity, precisely because it doesn't define interfaces. But does
| this harm PEP 246? I'm not sure.

Well, PEP 246 should be edited, IMHO, to assert that all 'implicit'
adaptions are out-of-scope, and if they are supported should be done
so under the direct control of the application developer.

-- 
Clark C. Evans                      Prometheus Research, LLC.
                                    http://www.prometheusresearch.com/
    o                               office: +1.203.777.2550 
  ~/ ,                              mobile: +1.203.444.0557 
 //
((   Prometheus Research: Transforming Data Into Knowledge
 \\  ,
   \/    - Research Exchange Database
   /\    - Survey & Assessment Technologies
   ` \   - Software Tools for Researchers
    ~ *


More information about the Python-Dev mailing list