LSP (was Re: Function.prototype.bind)

Graydon Hoare graydon at mozilla.com
Wed Sep 24 15:58:32 PDT 2008


waldemar at google.com wrote:
>> Waldemar Horwat wrote:
>>> Graydon Hoare wrote:
>>>> Quoting Liskov[1]:
>>>>
>>>>    "What is wanted here is something like the following substitution
>>>>     property: 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."
>>>>
>>>> Think it over. Imagine what you'd have to delete from any language you
>>>> use, for its "subtype" relation to conform to that definition.
>>> What?  For example, what would you have to delete from Java, ignoring
>>> the parts where a program can examine itself like reflection?
>> The big one is "method overriding in subtypes", though as you say there
>> are various other cases such as reflection. If I have a program that
>> uses some type:
>>
>>    class Mul {
>>      int f(int x, int y) { return x * y; }
>>    }
>>
>> I can form a subtype such that substituting the subtype for the
>> supertype in some program will likely change the behavior of the program:
>>
>>    class NotTheMulYoureLookingFor extends Mul {
>>      int f(int x, int y) { return x + y; }
>>    }
> 
> What does this have to do with your claim about the Liskov property? 
> Where in this example do you take an object o1 of type
> NotTheMulYoureLookingFor and prove that there is no object o2 of type Mul
> that satisfies the Liskov property?

This is seriously belaboring a point, but ... I'll try again. The LSP 
describes this subtype relationship here iff:

   for every object o1 of type NotTheMulYoureLookingFor:
     there is an object o2 of type Mul:
       such that for all programs P:
         the behavior of P(o2) is the same as P(o1)

The only wiggle room I can see here is if you're saying that instances 
like o1 are also "objects of type Mul", such that you can let o2=o1 and 
trivially satisfy it. But that reading seems totally backwards: the LSP 
is a principle for *defining* a subtype relation; it hardly seems useful 
to incorporate an existing subtype relation into its use of the phrase 
"object o2 of type T".

I think we're possibly talking past each other, or discussing different 
things? Possibly I've just misunderstood the issue all this time. All 
I'm saying is that in Java -- and most contemporary OO languages -- the 
subtype relation is defined (roughly) between classes in a way that is 
not very much like the way I usually interpret the LSP. Substituting an 
instance of a subclass doesn't preserve behavior of programs that 
previously used instances of the superclass. You can cook up *some* pair 
of classes that are substitutable in the Liskov sense -- and it's a good 
guideline during class design -- but it's not the way "subtype" (or at 
least "subclass") is defined in these languages.

(In later papers -- presumably when it was clear that subtypes in many 
languages *were* going to carry dynamic function tables -- Liskov and 
others revisited this issue, and arrived at the formalism of combining 
method contracts during overriding, such as is done in Sather, D and 
Eiffel. Java doesn't to that either. There's really very modest 
constraints on the behavior of a method.)

-Graydon


More information about the Es-discuss mailing list