[Python-Dev] PEP 246, redux

Alex Martelli aleax at aleax.it
Wed Jan 12 15:48:41 CET 2005


On 2005 Jan 12, at 15:00, Paul Moore wrote:

> On Wed, 12 Jan 2005 00:33:22 +0100, Alex Martelli <aleax at aleax.it> 
> wrote:
>> By imposing transitivity, you're essentially asserting that, if a
>> programmer forgets to code and register an A -> C direct adapter, this
>> is never a problem, as long as A -> B and B -> C adapters are
>> registered, because A -> B -> C will give results just as good as the
>> direct A -> C would have, so there's absolutely no reason to trouble
>> the programmer about the trivial detail that transitivity is being
>> used.
> [...]
>> paragraph, then this is just weird: since you're implicitly asserting
>> that any old A->?->C transitive adaptation is just as good as a direct
>> A->C, why should you worry about there being more than one such 2-step
>> adaptation available?  Roll the dice to pick one and just proceed.
>
> I know this is out-of-context picking, but I don't think I've ever
> seen anyone state that A->?->C is "just as good as" a direct A->C. I
> would have thought it self-evident that a shorter adaptation path is
> always better. And specifically, I know that Philip has stated that
> PyProtocols applies a shorter-is-better algorithm.

Yes, he has.  If A->C is registered as a direct adaptation, it gets 
used and everybody lives happily ever after.  The controversy comes 
when A->C is *NOT* registered as a direct adaptation.

If there is no degradation of information quality, etc, at any 
intermediate step, picking the shortest path is still sensible because 
of likely performance consideration.  Each adaptation step might put 
some kind of wrapper/proxy/adapter object in the mix, delegate calls, 
etc.  Of course, it's possible that some such wrappers are coded much 
more tighter &c, so that in fact some roundabout A -> X1 -> X2 -> C 
would actually be better performing than either A -> B -> C or A -> Z 
-> C, but using one of the shortest available paths appears to be a 
reasonable heuristic for what, if one "assumes away" any degradation, 
is after all a minor issue.

Demanding that the set of paths of minimal available length has exactly 
one element is strange, though, IF one is assuming that all adaptation 
paths are exactly equivalent except at most for secondary issues of 
performance (which are only adjudicated by the simplest heuristic: if 
those issues were NOT considered minor/secondary, then a more 
sophisticated scheme would be warranted, e.g. by letting the programmer 
associate a cost to each step, picking the lowest-cost path, AND 
letting the caller of adapt() also specify the maximal acceptable cost 
or at least obtain the cost associated with the chosen path).

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 (but then 
the idea of giving an error when two or more shortest-paths have the 
same length becomes dubious).

Even C++ at least lets a poor beleaguered programmer assert that a 
conversion (C++ does not have adaptation, but it does have conversion) 
is _EXPLICIT_, meaning that it only applies as a single isolated step 
and NOT as a part of one of those automatic transitive 
conversion-chains which so often produce amazing, hell-to-debug 
results.  That's the wrong default (explicit should be the default, 
"usable transitively" should need to be asserted outright), explainable 
by the usual historical and backwards compatibilty reason (just like 
having methods default to non-virtual, etc, etc), but at least it's 
THERE -- a way to stop transitivity and restore sanity.  I have not yet 
seen PJE willing to compromise on this point -- having two categories 
or grades of adaptations, one "perfect, lossless, noiseless, 
impeccable" usable transitively and one "sublunar" NOT usable 
transitively.  ((If he was, we could still argue on which one should be 
the default;-))


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 (I have no 
reason to doubt that any way to induce transitivity without very 
clearly stating that one WANTS that effect can be extremely bug-prone).

So, yes, I'd _also_ love to have two grades of inheritance, one of the 
"total commitment" kind (implying transitivity and whatever), and one 
more earthly a la ``I'm just doing some convenient reuse, leave me 
alone''.  Here, regretfully, I'll admit C++ has the advantage, since 
``private inheritance'' is exactly that inferior, implementation-only 
kind (I'm perfectly happy with Python NOT having private methods nor 
attributes, but private INHERITANCE sometimes I still miss;-).  Ah 
well, can't have everything.  While I hope we can offer some lifesaver 
to those poor practicing programmers whose inheritance-structures 
aren't always perfect and pristine, if the only way to treat 
interface-inheritance is the Hyperliskovian one, ah well, we'll 
survive.

BTW, Microsoft's COM's interfaces ONLY have the "inferior" kind of 
inheritance.  You can say that interface ISub inherits from IBas: this 
means that ISub has all the same methods as IBas with the same 
signatures, plus it may have other methods; it does *NOT* mean that 
anything implementing ISub must also implement IBas, nor that a 
QueryInterface on an ISub asking for an IBas must succeed, or anything 
of that kind.  In many years of COM practice I have NEVER found this 
issue to be a limitation -- it works just fine.  I do not know CORBA 
anywhere as well as I do COM, but, doesn't CORBA interface inheritance, 
per OMG's standards, also work that way?


Alex



More information about the Python-Dev mailing list