3

I have searched for this question but could not find a good answer for my case.

Suppose I have a SuperClass for a bank loan with properties Amount and InterestRate.

public class BankLoan{
   public double Amount {get; set;}
   public double InterestRate {get; set;}
}

Then I create a derived class called SmallLoan, which will have a variable InterestRate based on its amount.

public class SmallLoan{
   public SmallLoan(){
     InterestRate = CalculateInterest();
   }

   private double CalculateInterest(){
      if(Amount < 100)
         return 0.10;
      else
         return 0.05;
   }
}

Would this be violating the LSP? I would think that it doesn't, because even if an instance of SmallLoan tries to call CalculateInterest outside of the class definition, it's going to throw an error, not related to the substitution but simply because it has a different access modifier. Even if only BankLoan existed and it had the same private method, a call to it from the outside would also result in an error.

But I can see how some people would say that the presence of the error in general is a violation of the principle.

Lastly: I am aware that these classes might not be the best and brightest implementations of inheritance or even just basic class design, but the question isn't about that, I merely want to know if private methods are a violation of LSP, and I chose to illustrate it with this very simple example.

2
  • 5
    "because it has a different access modifier" - even if the method was public, that wouldn't in itself be an LSP violation. Subclasses are free to provide extra methods; the problem revolves around what those methods do with respect to the "promises" made by the superclass ("the contract"). If the the method can do something that will cause a surprise to code that polymorphically uses the instance through a variable that's typed as the superclass, then you have a violation. – Filip Milovanović Dec 8 '20 at 12:27
  • "might not be best and brightest implementations of inheritance" There's no inheritence here, or subtyping of any kind. Did you forget to make SmallLoan inherit from BankLoan? – Alexander Dec 23 '20 at 17:02
7

Let's start with a definition: 'if S is a subtype of T, then objects of type T may be replaced with objects of type S'

The fact that S or T may or may not have a private method that handles part of the behavior for the public interface in itself can not be a violation of the above principle. Since (normally) private methods are invisible and cannot be called from the outside, they are not part of the interface and clients cannot depend on it. Therefor the fact that one type has delegated some of it's inner workings to a private method, does not hinder the substitution of objects of this type for objects of it's super or derived type.

Note that I'm not saying that your code example isn't violating LSP. LSP is also about correct behavior and the way you set InterestRate in the constructor of SmallLoan with a reference to Amount which is null at that point could be considered a violation. But let's ignore this, since you said the question is not about the implementation of your example, but simply whether private methods are a LSP violation.

1
  • In C#, a double cannot be null even if not initialized. The default value is 0. – Jared Goguen Dec 24 '20 at 19:14
0

If you were to use a BankLoan object in code somewhere, the reference could be replaced with an implementation of SmallLoan (since a SmallLoan is a BankLoan), and the application itself would not know any difference. The private methods inside of the implementation would not matter.

However, if you have a SmallLoan object in code, you would not be able to replace the reference with a BankLoan implementation (since a BankLoan is not a SmallLoan). This is where the violation would occur. The two instances cannot equally replace each other.

In order to take advantage of the LSP, you would instead want something along the lines of an interface, such as an ILoan, that would describe the behavior/properties that all implementations would need. At that point, a ILoan reference could be replaced with anything that implements the ILoan interface. If SmallLoan and BankLoan both implemented the interface, they could easily replace each other at the reference level. Private methods would have no effect on that.

I may be wrong on my interpretation of it, but the LSP cares about having expected behaviors/properties, rather than on how they are implemented.

0

Clearly if I have an object with a property “InterestRate” with a getter and setter then I expect that calling the setter to change the value returned by the getter and the interest calculation. Your “SmallLoan” class either doesn’t meet that behaviour are it behaves very strangely. That’s where your violation is.

You could have a baseclass “GenericLoan” with only a public getter and a protected setter for the interest rate, two subclasses “BankLoan” and “SmallLoan”, with “BankLoan” having a public setter. You can’t set the interest rate on a generic loan because not all subclasses understand it.

PS. Private methods or properties are just an implementation detail. They don’t have anything to do with LSP at all. Public methods in a subclass still have nothing to do with LSP, because they can only be called if you have a reference to a subclass object. At some point there must be a difference, otherwise why would you want a subclass if it is the exact same as the base class?

0

No private methods do not break LSP because the subclass still contains the base class methods and attributes, so we can still use SmallLoan as BankLoan but not BankLoan as SmallLoan without using a cast

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.