[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