The Liskov Substitution Principle states:
Invariants of the supertype must be preserved in a subtype.
I'm particularly interested with the intersection of this principle and polymorphism. In particular subtype-polymorphism though, in fact, this seems to be the case with parametric polymorphism and Haskell type classes.
So, I know that functions are subtypes when their arguments are contravariant and their return types covariant. We can assume that methods are just functions with an implicit "self" argument. However, this seems to imply that if a subclass overrides a method of the parent, it is no longer a subtype, as one of it's methods is no longer a subtype.
For example. Take the following pseudo-code:
class Parent:
count : int
increment : Parent -> ()
{
count += 1
}
class Child inherits Parent:
increment : Child -> ()
{
count += 2
}
So going back to the LSP: can we say that a property of Parent.increment()
should hold for Child.increment()
even though these two don't obey a strict subtyping relation?
More generally my question is: how do the rules of subtyping interface with the more specific arguments of polymorphic functions and what is the correct way of thinking about these two concepts together?