[Python-Dev] PEP 246, redux (original) (raw)

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