-2

Code below does not compile. Why can't I pass in SomeTypeString as an argument of overridden method in SomeInst?

trait SomeType
abstract class SomeClass[T] {
  def method(someType: SomeType): Unit
}
class SomeTypeString extends SomeType

class SomeInst extends SomeClass[String]() {
  override def method(someType: SomeTypeString): Unit = ???
}
user_1357
  • 7,766
  • 13
  • 63
  • 106

1 Answers1

4

Instances of a supertype must be replaceable by instances of a subtype without altering the desirable properties of the program. That is the very definition of "subtype" using the Liskov Substitution Principle, which gives a behavioral contract-based notion of subtyping that takes aliasing into account.

This means that everywhere I have an instance of SomeClass I can also use an instance of SomeInst. However, in your example that is not true: if I have an instance i of SomeClass then I can call i.method(s), where s is an instance of SomeType. According to the Liskov Substitution Principle, I must be able to do the same, when I call ii.method(s), where ii is an instance of SomeType. But I am not allowed to. I am only allowed to pass an instance of SomeTypeString.

Ergo, your example violates the Liskov Substitution Principle, or, in other words, SomeInst is not allowed to be a subtype of SomeClass.

Note that this is actually not new. This was already known in the 1960s even before Barbara Liskov formulated the LSP, these are just the standard subtyping rules for functions:

  • functions are contravariant in their parameter types
  • functions are covariant in their return types
Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653