# SOLID : Liskov Substitution Principle (Part 2)

In the first part of the post, we visited the core definition of Liskov Substitution principle and took time to understand the problem using an example. In this second part, we would take time to understand some of the governing rules of the principle.

The rules that needs to be followed for LSP compliance can be broadly categorized into mainly two categories.

• Contract Rules
• Variance Rules

Let us examine the Contract Rules first.

Contact Rules
The three contact rules are defined as follows.
* Preconditions cannot be strengthened in a subtype.
* Postconditions cannot be weakened in a subtype.
* Invariants—conditions that must remain true—of the supertype must be preserved in a subtype

Let us examine each of them breifly.

Preconditions cannot be strengthend in a subtype.

Preconditions are conditions that are necessary for a method to run reliably. For example, consider a method in a school application, which returns the count of students above specified age.

```public virtual int GetStudentCount(int minAge)
{
if(minAge <=0)
throw new ArgumentOutOfRangeException("Invalid Age");
return default; // For demo purpose
}
```

As observed in the above method, a non-positive value for age needs to be flagged as an exception and method should stop executing. The method does this check as the first step before it executes any logic related to the funcationlity of the method and thereby preventing the method execution unless the parameters are valid. This is a typical example of preconditions. There are other ways to add preconditions, but that would be out of scope of the current context.

So what happens if the precondition is strengthed. Let us assume that the application for Kindergarden for the school derieves from the same class, but adds another precondition.

```public override int GetStudentCount(int minAge)
{
if(minAge <=0) throw new ArgumentOutOfRangeException("Invalid Age"); if(minAge >=5)
throw new ArgumentOutOfRangeException("Invalid Age");
return default; // For demo purpose
}
```

This creates a conflict in the calling class. The caller was invoking the method from the base Class, it would not throw an exception if the value is greater then 5. However, if the caller was invoking the method from the Child Class, it would now throw an exception, thanks to the new precondition we have added. Let’s demonstrate the same using Unit Tests.

```[Test]
[TestCaseSource(typeof(Preconditions), nameof(TestCases))]
public void GetStudentCount(School school,int age)
{
Assert.GreaterOrEqual(school.GetStudentCount(age), 0);
}

public static IEnumerable TestCases
{
get
{
yield return new TestCaseData(new School(), 7);
yield return new TestCaseData(new Kindergarden(), 7);
}
}
}

```

The Unit Tests show that the strengthening of Preconditions would now indirectly force the caller to violate the fact that it should not make any assumptions about the type it is acting on (and thereby violating Open Closed Principle).

Post Conditions cannot be weakend in a subtype

During the execution of the method, the state of the object is most likely to be mutated, opening the door of possiblity that the method might leave the object in an invalid state due to errors in the method. Post Conditions ensures that the state of the object is in a valid state when the method exits.

Much similiar to the Preconditions, the Post Conditions are commonly implemented using Guard clauses, which ensure the state is valid after the execution of logic (any code that might alter the state of the object) associated with the method. For the same reason, the Post Conditions are placed at the end of the method.

The behavior of Post Conditions in sub-classes is the complete opposite of what happens with Pre Conditions. The Post Conditions, if weakened, could l;ead to existing clients to behave incorrectly. Let us explore a scenario. We will write the Unit Tests first.

```[Test]
[TestCaseSource(typeof(Postconditions), nameof(TestCases))]
public void TestLabFeeForSchool(School school, long studentId)
{
Assert.Greater(school.CalculateLabFees(studentId),0);
}

public static IEnumerable TestCases
{
get
{
yield return new TestCaseData(new School(), 7);
}
}
```

The above Test Case ensures that the CalculateLabFees method returns a positive and non-zero value as result. Let us assume that School.CalculateLabFees method was defined as following.

```public class School
{
public virtual decimal CalculateLabFees(long studentId)
{
var labFee = MockMethodForCalculatingLabFees(studentId);

if (labFee <= 0)
return 1000;
return labFee;
}

private decimal MockMethodForCalculatingLabFees(long studentID)
{
return default;
}
}
```

The Post Condition in the base class ensures that if the labFee is less than or equal to zero, a default value of 1000 is returned. The Test Case would pass successfully with the instance of class. The CalculateLabFees method would return a positive, non-zero value as expected by the Unit Test.

Now, let us assume the Kindergarden Implementation. The Kindergarden doesn’t have Lab Fees and hence, would return a default value 0 for the CalculateLabFee method.

```public class Kindergarden : School
{
public override decimal CalculateLabFees(long studentId)
{
return 0;
}
}
```

As you can notice the Post Condition has been weakened in the Child Class. This would cause issues with client which would expect a positive response, as with the Unit Test Case. This highlights another instance where significance of honoring LSP is highlighted.

Invariants must be maintained

An invariant describes a condition of a process that remains true before the process begins and after the process ends, until ofcourse the object is out of scope.

Consider the following base class.

```public class Student
{
public string Name{ get; set; }

public void CheckInvariants()
{
if (string.IsNullOrEmpty(Name))
Name = "Name Not Assigned";
}
public virtual void AssignName(string name)
{
CheckInvariants();
Name = name;
CheckInvariants();
}
}
```

The class requires the Name property to be always have a value. The CheckInvariants method assigns a default value if the clause is violated. Let us assume we have an sub class NurseryStudent.

```public class NurseryStudent : Student
{
public override void AssignName(string name)
{
Name = name;
}

}
```

The author of NurseryStudent forgots to ensure the Invariants holds true after the AssignName exits. This is a violation of LSP as a client using the SuperClass would expect the Name to always have a value. Consider the following code.

```[Test]
[TestCaseSource(typeof(Invariants), nameof(TestCases))]
public void TestInvariants(Student student,string name)
{
student.AssignName(name);
Assert.Greater(student.Name.Length, 0);
}

public static IEnumerable TestCases
{
get
{
yield return new TestCaseData(new Student(), string.Empty);
yield return new TestCaseData(new NurseryStudent(), string.Empty);
}
}
```

The Unit Test Case would fail

Let’s write the Unit Test Case before writing the example for sub class.

```[Test]
[TestCaseSource(typeof(Invariants), nameof(TestCases))]
public void TestInvariants(Student student,string name)
{
student.AssignName(name);
Assert.Greater(student.Name.Length, 0);
}

public static IEnumerable TestCases
{
get
{
yield return new TestCaseData(new Student(), null);
yield return new TestCaseData(new NurseryStudent(), null);
}
}
```

The Test Case would fail when an instance of NurserStudent is passed to the method as the Name property would have an unexpected value of null when leaving the AssignName method. This would cause exceptions in all clients which expects the behavior of invariants are retained by any subclass of the Student.

In this post we explored the Contract Rules for LSP. In the part, we would explore the variance rules involved for conforming with LSP. All code samples given in the post are available in my Github

# SOLID : Liskov Substitution Principle (Part 1)

The “L” in SOLID stands for Liskov Substitution Principle, named after Barbara Liskov, who initially introduced in 1987 keynote address. LSP provides guidelines for creating inheritence heirachy where a client can use any class or subclass without breaking the expected behavior.

We will begin by looking at the official definition first.

If S is a subtype of T, then objects of type T may be replaced with objects of type S,without breaking the program.

It would be unwise to explain this theoratically, hence like always, let hit the Visual Studio and write some code. I would like borrow an example given by Tim Correy in his famous video.

Assume we have an Employee class defined as follows.

```public class Employee
{
public string Name{get;set;}
public Employee AssignedManager{get;protected set;}
public virtual double GetPay()
{
var currentSalary = 500;
Console.WriteLine(\$"Current Pay {currentSalary}");
return currentSalary;
}

public virtual void AssignManager(Employee manager)
{
Console.WriteLine("Manager Assigned");
AssignedManager = manager;
}
}
```

Now let’s assume we have a Manager class, which inherits from Employee

```public class Manager:Employee
{
public override double GetPay()
{
var currentSalary = 750;
Console.WriteLine(\$"Current Pay {currentSalary}");
return currentSalary;
}

public override void AssignManager(Employee manager)
{
Console.WriteLine("Manager Assigned");
AssignedManager = manager;
}
}
```

Let’s write some client code now which consumes these classes.

```var manager = new Manager();
manager.Name = "John Doe";
manager.GetPay();

var programmer = new Employee();
programmer.Name = "Roel Doel";
programmer.GetPay();
programmer.AssignManager(manager);
```

Output

```Current Pay 750
Current Pay 500
Manager Assigned
```

As you can observe, the output is perfectly fine. Let us try making some changes to the Client Code now. Let us replace the Employee class (programmer instance) with Manager.

```var manager = new Manager();
manager.Name = "John Doe";
manager.GetPay();

var programmer = new Manager();
programmer.Name = "Roel Doel";
programmer.GetPay();
programmer.AssignManager(manager);
```

Output

```Current Pay 750
Current Pay 750
Manager Assigned
```

This has turned out fine as well. Yes the output is different, which is expected considering the Pay for Manager and Employee are different, but the client hasn’t behaved unexpectedly. Let’s write one more class, inheriting from Employee and call it CEO.

```public class CEO:Employee
{
public override double GetPay()
{
var currentSalary = 750;
Console.WriteLine(\$"Current Pay {currentSalary}");
return currentSalary;
}

public override void AssignManager(Employee manager)
{
throw new Exception("Am the CEO, no Manager for me !!");
}
}
```

The difference this time is of course the CEO doesn’t have a Manager and it raises an exception in the AssignManager method. Let’s head back to out Client code and replace Employee with CEO in our original code.

```var manager = new Manager();
manager.Name = "John Doe";
manager.GetPay();

var programmer = new CEO();
programmer.Name = "Roel Doel";
programmer.GetPay();
programmer.AssignManager(manager);
```

Output

```Exception:Am the CEO, no Manager for me !!
```

Aha, we have an exception here. When replaced the Employee (Base type) with a subtype (CEO), the expected behavior of program has been broken. This is a violation of LSP.

Let’s examine the violation further. It is often said that Inheritence is the IS-A relation. However, if you truely examine CEO and Employee, do they follow a IS-A relation in every sense ? Not really, not according the current definition of Employee. Yes, that is right. The problem doesn’t quite lie in CEO, but it originate from the definition of Employee class. While designing the Employee class, we “assumed” that all Employees would have a manager.

So what is the best solution for this scenario ? What if we were to ensure the Employee class had only those functionalities which are common to every employee ? Obviously, the Manager is not applicable for everyone, so let’s remove it and create an interface which contains only the basic employee functionalities.

```public interface IBaseEmployee
{
string Name{get;set;}
double GetPay();
}

public abstract class BaseEmployee:IBaseEmployee
{
public string Name{get;set;}
public virtual double GetPay(){ return 0;}
}
```

Remember, we still have to consider the Manager assignment. What we would do here is define another interface IHasManager, which would wrap the functionalities required for Employees who has Manager.

```public interface IHasManager
{
IBaseEmployee AssignedManager{get;set;}
void AssignManager(IBaseEmployee manager);
}
```

Let’s now define our Employee and Manager classes.

```public class Employee:BaseEmployee,IHasManager
{
public IBaseEmployee AssignedManager{get; set;}
public override double GetPay()
{
var currentSalary = 500;
Console.WriteLine(\$"Current Pay {currentSalary}");
return currentSalary;
}

public virtual void AssignManager(IBaseEmployee manager)
{
Console.WriteLine("Manager Assigned");
AssignedManager = manager;
}

}

public class Manager:BaseEmployee,IHasManager
{
public IBaseEmployee AssignedManager{get; set;}
public override double GetPay()
{
var currentSalary = 750;
Console.WriteLine(\$"Current Pay {currentSalary}");
return currentSalary;
}

public void AssignManager(IBaseEmployee manager)
{
Console.WriteLine("Manager Assigned");
AssignedManager = manager;
}
}
```

As you can see, the Manager and Employee inherits from BaseEmployee and implements the IHasManager interface. The next step is to define our CEO Class, and this time, we know that he doesn’t need a Manager.

```public class CEO:BaseEmployee
{

public override double GetPay()
{
var currentSalary = 750;
Console.WriteLine(\$"Current Pay {currentSalary}");
return currentSalary;
}

}
```

That’s it. Let’s rewrite our Client code now.

```var manager = new Manager();
manager.Name = "John Doe";
manager.GetPay();

var programmer = new Employee();
programmer.Name = "Roel Doel";
programmer.GetPay();
programmer.AssignManager(manager);

```

The above code compiles and executes as expected. Let’s replace the Employee with a Manager first.

```var manager = new Manager();
manager.Name = "John Doe";
manager.GetPay();

var programmer = new Manager();
programmer.Name = "Roel Doel";
programmer.GetPay();
programmer.AssignManager(manager);
```

That works fine as well. Let’s try again, and this time replace with CEO.

```var manager = new Manager();
manager.Name = "John Doe";
manager.GetPay();

var programmer = new CEO();
programmer.Name = "Roel Doel";
programmer.GetPay();
programmer.AssignManager(manager);
```

Not surprisingly, that doesn’t compile at all. CEO doesn’t have the AssignManager method as it doesn’t implement the IHasManager interface. Your client no longer have unexpected behavior as such errors are caught during compilation.

That was pretty easy, isn’t it ? But we are not done yet. There is more to the definition of LSP. In the next part of this series, we will examine the Contact and Variance rules which must be followed for LSP compliance.