[Python-Dev] PEP 246, redux

Paul Moore p.f.moore at gmail.com
Thu Jan 13 11:35:39 CET 2005


On Wed, 12 Jan 2005 21:50:14 -0600, Ian Bicking <ianb at colorstudy.com> wrote:
> Phillip J. Eby wrote:
> > At 04:07 PM 1/12/05 -0600, Ian Bicking wrote:
> >
> >> It also seems quite reasonable and unambiguous that a path object
> >> could be adapted to a IReadableFile by opening the file at the given
> >> path.
> >
> >
> > Not if you think of adaptation as an "as-a" relationship, like using a
> > screwdriver "as a" hammer (really an IPounderOfNails, or some such).  It
> > makes no sense to use a path "as a" readable file, so this particular
> > adaptation is bogus.
> 
> I started to realize that in a now-aborted reply to Steven, when my
> defense of the path->IReadableFile adaptation started making less sense.

I think I'm getting a clearer picture here (at last!)

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.

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.

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?

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.

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.

>   It's *still* not intuitively incorrect to me, but there's a couple
> things I can think of...
> 
> (a) After you adapted the path to the file, and have a side-effect of
> opening a file, it's unclear who is responsible for closing it.
> (b) The file object clearly has state the path object doesn't have, like
> a file position.
> (c) You can't  go adapting the path object to a file whenever you
> wanted, because of those side effects.

In the context of my example above, I was assuming that C was an
"interface" (whatever that might be). Here, you're talking about
adapting to a file (a concrete class), which I find to be a much
muddier concept.

This is very much a "best practices" type of issue, though. I don't
see PEP 246 mandating that you *cannot* adapt to concrete classes, but
I can see that it's a dangerous thing to do.

Even the string->path adaptation could be considered suspect. Rather,
you "should" be defining an IPath *interface*, with operations such as
join, basename, and maybe open. Then, the path class would have a
trivial adaptation to IPath, and adapting a string to an IPath would
likely do so by constructing a path object from the string. From a
practical point of view, the IPath interface adds nothing over
adapting direct to the path class, but for the purposes of clarity,
documentation, separation of concepts, etc, I can see the value.

> So those are some more practical reasons that it *now* seems bad to me,
> but that wasn't my immediate intuition, and I could have happily written
> out all the necessary code without countering that intuition.  In fact,
> I've misused adaptation before (I think) though in different ways, and
> it those mistakes haven't particularly improved my intuition on the
> matter.  If you can't learn from mistakes, how can you learn?
> 
> One way is with principles and rules, even if they are flawed or
> incomplete.  Perhaps avoiding adaptation diamonds is one such rule; it
> may not be necessarily and absolutely a bad thing that there is a
> diamond, but it is often enough a sign of problems elsewhere that it may
> be best to internalize that belief anyway.  Avoiding diamonds alone
> isn't enough of a rule, but maybe it's a start.

Some mistakes are easier to avoid if you have the correct conceptual
framework. I suspect that interfaces are the conceptual framework
which make adaptation fall into place. If so, then PEP 246, and
adaptation per se, is always going to be hard to reason about for
people without a background in interfaces.

Hmm. I think I just disqualified myself from making any meaningful comments :-)

Paul.


More information about the Python-Dev mailing list