[Python-Dev] PEP 246, redux

Michael Chermside mcherm at mcherm.com
Wed Jan 12 18:46:46 CET 2005


This is a collection of responses to various things that don't appear
to have been resolved yet:

Phillip writes:
> if a target protocol has optional aspects, then lossy adaptation to it is
> okay by definition.  Conversely, if the aspect is *not* optional, then
> lossy adaptation to it is not acceptable.  I don't think there can really
> be a middle ground; you have to decide whether the information is required
> or not.

I disagree. To belabor Alex's example, suppose LotsOfInfo has first, middle,
and last names; PersonName has first and last, and FullName has first,
middle initial and last. FullName's __doc__ specifically states that if
the middle name is not available or the individual does not have a middle
name, then "None" is acceptable.

Converting LotsOfInfo to FullName via PersonName results in None for the
middle name. But that's just not right... it _should_ be filling in the
middle initial because that information IS available. It's technically
correct in a theoretical sort of a way (FullName never PROMISES that
middle_initial will be available), but it's wrong in a my-program-doesn't-
work-right sort of way, because it HAS the information available yet
doesn't use it.

You're probably going to say "okay, then register a LotsOfInfo->FullName
converter", and I agree. But if no such converter is registered, I
would rather have a TypeError then an automatic conversion which produces
incorrect results. I can explicitly silence it by registering a trivial
converter:

    def adapt_LotsOfInfo_to_FullName(lots_of_info):
        person_name = adapt(lots_of_info, PersonName)
        return adapt(person_name, FullName)

but if it just worked, I could only discover that by being clever enough
to think of writing unit test for middle name.

------------------

Elsewhere, Phillip writes:
> If you derive an interface from another interface, this is supposed to mean
> that your derived interface promises to uphold all the promises of the base
> interface.  That is, your derived interface is always usable where the base
> interface is required.
>
> However, oftentimes one mistakenly derives an interface from another while
> meaning that the base interface is *required* by the derived interface,
> which is similar in meaning but subtly different.  Here, you mean to say,
> "IDerived has all of the requirements of IBase", but you have instead said,
> "You can use IDerived wherever IBase is desired".

Okay, that's beginning to make sense to me.

> it's difficult because intuitively an interface defines a *requirement*, so
> it seems logical to inherit from an interface in order to add requirements!

Yes... I would fall into this trap as well until I'd been burned a few times.

------------------

Alex summarizes nicely:
> Personally, I disagree with having transitivity at all, unless perhaps
> it be restricted to adaptations specifically and explicitly stated to
> be "perfect and lossless"; PJE claims that ALL adaptations MUST,
> ALWAYS, be "perfect and lossless" -- essentially, it seems to me, he
> _has_ to claim that, to defend transitivity being applied
> automatically, relentlessly, NON-optionally, NON-selectively
      [...]
> Much the same applies to inheritance, BTW, which as PJE has pointed out
> a few times also induces transitivity in adaptation, and, according to
> him, is a more likely cause of bugs than chains of adapters

But Alex goes on to say that perhaps we need two grades of adaptations
(perfect and real-world) and two grades of interface inheritance (perfect
and otherwise) so that the transitivity can be (automatically) invoked
only for the perfect ones. That feels to me like excessive complexity:
why not just prohibit transitivity? What, after all, is the COST of
prohibiting transitivity?

For the first case (adapter chains) the cost is a N^2 explosion in the
number of adapters needed. I said I thought that N would be small, but
Phillip (who knows what he's talking about, don't get me wrong here)
says that it's big enough to be mildly annoying at times to Twisted
and Eclipse developers.

For the second case (interface inheritance), I haven't yet thought
through clearly how at affects things... in fact, it sort of seems like
there's no good way to _prevent_ "transitivity" in this case short
of prohibiting interface inheritance entirely. And, as Phillip points
out to me (see above) this is a more common type of error.

Gee... I'm understanding the problem a little better, but elegant
solutions are still escaping me.

-- Michael Chermside



More information about the Python-Dev mailing list