[Python-Dev] defaultdict proposal round three
Alex Martelli
aleaxit at gmail.com
Tue Feb 21 01:55:34 CET 2006
On Feb 20, 2006, at 3:04 PM, Brett Cannon wrote:
...
>> - "Yes and it should be the only constructor argument." This is my
...
> While #3 is my preferred solution as well, it does pose a Liskov
> violation if this is a direct dict subclass instead of storing a dict
How so? Liskov's principle is (in her own words):
If for each object o1 of type S there is an object o2 of type T such
that for all programs P defined in terms of T, the behavior of P is
unchanged when o1 is substituted for o2 then S is a subtype of T.
How can this ever be broken by the mere presence of incompatible
signatures for T's and S's ctors?
I believe the principle, as stated above, was imperfectly stated, btw
(it WAS preceded by "something like the following substitution
property", indicating that Liskov was groping towards a good
formulation), but that's an aside -- the point is that the principle
is about substitution of _objects_, i.e., _instances_ of the types S
and T, not about substitution of the _types_ themselves for each
other. Instances exist and are supposed to satisfy their invariants
_after_ ctors are done executing; ctor's signatures don't matter.
In Python, of course, you _could_ call type(o2)(...) and possibly get
different behavior if that was changed into type(o1)(...) -- the
curse of powerful introspection;-). But then, isn't it trivial to
obtain cases in which the behavior is NOT unchanged? If it was
always unchanged, what would be the point of ever subclassing?-) Say
that o2 is an int and o1 is a bool -- just a "print o2" already
breaks the principle as stated (it's harder to get a simpler P than
this...).
Unless you have explicitly documented invariants (such as "any 'print
o' must emit 1+ digits followed by a newline" for integers), you
cannot say that some alleged subclass is breaking Liskov's property,
in general. Mere "change of behavior" in the most general case cannot
qualify, if method overriding is to be any use; such change IS
traditionally allowed as long as preconditions are looser and
postconditions are stricter; and I believe than in any real-world
subclassing, with sufficient introspection you'll always find a
violation E.g., a subtype IS allowed to add methods, by Liskov's
specific example; but then, len(dir(o1)) cannot fail to be a higher
number than len(dir(o2)), from which you can easily construct a P
which "changes behavior" for any definition you care to choose.
E.g., pick constant N as the len(dir(...)) for instances of type T,
and say that M>N is the len(dir(...)) for instances of S. Well,
then, math.sqrt(N-len(dir(o2))) is well defined -- but change o2 into
o1, and since N-M is <0, you'll get an exception.
If you can give an introspection-free example showing how Liskov
substitution would be broken by a mere change to incompatible
signature in the ctor, I'll be grateful; but I don't think it can be
done.
Alex
More information about the Python-Dev
mailing list