[Python-Dev] PEP 246, redux
Guido van Rossum
gvanrossum at gmail.com
Wed Jan 12 16:45:55 CET 2005
[Alex]
> 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.
I would think that the main reason for preferring the shortest path is
the two degenerate cases, A->A (no adaptation necessary) and A->C (a
direct adapter is available). These are always preferable over longer
possibilities.
> Demanding that the set of paths of minimal available length has exactly
> one element is strange, though,
I think you're over-emphasizing this point (in several messages);
somehow you sound a bit like you're triumphant over having found a bug
in your opponent's reasoning.
[...]
> 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''.
I'll bet that the list of situations where occasionally you wish you
had more control over Python's behavior is a lot longer than that, and
I think that if we started implementing that wish list (or anybody's
wish list), we would soon find that we had destroyed Python's charming
simplicity.
My personal POV here: even when you break Liskov in subtle ways, there
are lots of situations where assuming substitutability has no ill
effects, so I'm happy to pretend that a subclass is always a subtype
of all of its base classes, (and their base classes, etc.). If it
isn't, you can always provide an explicit adapter to rectify things.
As an example where a subclass that isn't a subtype can be used
successfully, consider a base class that defines addition to instances
of the same class. Now consider a subclass that overrides addition to
only handle addition to instances of that same subclass; this is a
Liskov violation. Now suppose the base class also has a factory
function that produces new instances, and the subclass overrides this
to produce new instances of the subclass. Then a function designed to
take an instance of the base class and return the sum of the instances
produced by calling the factory method a few times will work perfectly
with a subclass instance as argument. Concrete:
class B:
def add(self, other: B) -> B: ...
def factory(self) -> B: ...
class C(B):
def add(self, other: C) -> C: ... # "other: C" violates Liskov
def factory(self) -> C: ...
def foo(x: B) -> B:
x1 = x.factory()
x2 = x.factory()
return x1.add(x2)
This code works fine in today's python if one leaves the type
declarations out. I don't think anybody is served by forbidding it.
--
--Guido van Rossum (home page: http://www.python.org/~guido/)
More information about the Python-Dev
mailing list