Ali Alnader
Ali Alnader

Reputation: 303

Breaking Liskov substitution principle

I have the following code

public class A 
{
      public double foo(double y) 
      {
             return real_value;
      }
}

where the input for the foo method -1 < y < 1 and the result of the function is a real number greater than zero.

Then I have the inherited class B which inherit the class A and override the method foo.

public class B extends A 
{
      public override double foo(double y)
      {
         return real_value;
      }
}

where the input for the foo method 0 < y < 1 and the result of the function is any real number.

Is the Liskov Substitution principle violated here?

thanks in advance.

Upvotes: 3

Views: 2423

Answers (2)

hce
hce

Reputation: 1167

Assuming, that you want to use B as a subtype of A in your program:
Yes, your code clearly violates LSK.

Why?
Arguments should be contravariant.

What does that mean?
Liskov Principle assures, that your program behaves unchanged if your sub type B is replaced by the base type A.

Or more accurately (by Barbara Liskov, 1987):

“If for each object o1 of type B there is an object o2 of type A
such that for all programs P defined in terms of A, the behaviour of P is unchanged
when o1 is substituted for o2, then B is a subtype of A”.

For example:

   class Duck               { void fly(int   height) {} }
   class RedheadDuck : Duck { void fly(long  height) {} }
   class RubberDuck : Duck  { void fly(short height) {} }

   class LSPDemo
   {
      public void Main()
      {
         Duck p;

         p = new Duck();
         p.fly(int.MaxValue); // Expected behaviour

         p = new RedheadDuck();
         p.fly(int.MaxValue); // OK   

         p = new RubberDuck();
         p.fly(int.MaxValue); // Fail 
      }
   }

=> the program behaves unchanged, if the argument is contravariant.
=> e.g. base type <= sub type
=> RubberDuck violates this principle, as it does not allow all values of the base type Duck

In your code the type for the base class A foo would expect argument values -1 < y < 1
Your sub class B foo would expect argument values 0 < y < 1
If your program would replace the sub class with the base class, your program would not behave as expected for foo regarding values <= 0.

EDIT: Although you use double as type for your arguments on both foo methods, I assume that you guard your methods by checking the values and their scope. This would cause the described fail, analogous to the example.

P.S.: Yes it depends on the contract you define for foo. Assuming, that you want to use B as a sub type of A, then it violates the LSK. Otherwise it just a method overriding.

Upvotes: 6

serge
serge

Reputation: 1022

Indeed, your overridden function breaks the contract of base function so the Liskov principle is not really useful here. However, if you add a parameter like "processing mode" to base function, the L-principle works perfectly (overridden function will call base function for all old processing cases).

Upvotes: 0

Related Questions