Question:
If I understand correctly, then the principle of Barbara Liskov recommends using inheritance only to extend the functionality, and not replace it, while polymorphism allows you to change the behavior of heirs. It seems to me that these two principles contradict. Explain where I'm wrong.
Answer:
The Liskov principle is not about expanding or replacing functionality, but about respecting the contract.
Code that works with base class objects should work the same way if you start using descendants instead of these objects. At the same time, you can both extend the methods of base classes and replace them – this, in general, is a detail of your implementation, which users of the class are not even interested in.
Here, perhaps, it is more important to discuss what a breach of contract is. Speaking specifically about methods, they have input parameters and a result. The method without violating the contract does not require anything extra from the input parameters.
For example, we have a collection interface with a count
property and a getByIndex()
method. The index to get an element in the collection must be between 0 and count - 1
.
You are inventing a StringUtf8
collection. In UTF-8, different characters can require different numbers of bytes to store: 1, 2, 3, and so on. An implementation where count
returns the number of bytes in a string and index
allows you to get elements character by character would be a bug, because the contract of the interface would be violated in that case.
On the other hand, a non-contractual method adds nothing to the output. Let's imagine that the collection has a findIndex()
method that returns the index of the element in the collection if it is there and -1 if it is not there.
But for a sorted array, you want to return a place where an element can be inserted if it's not in the array. Usually this place is returned as a negative number -1, -2, -3, to which one must add 1 and then change the sign. Such a decision would also be a breach of contract.
It is more correct to leave the behavior of the findIndex()
method correct from the point of view of the interface, and add an additional method with the desired behavior to the sorted array.