Consider the following code:
class Parent {
def parentMethod = println("parent method")
}
class Child extends Parent {
override def parentMethod = println("parent method overriden")
def childMethod = println("child method")
}
val p: Parent = new Child
p.isInstanceOf[Child] // true
// p.childMethod // doesn't compile
p.asInstanceOf[Child].childMethod // child method
p.parentMethod // parent method overriden
p
has static (compile-time) type Parent
but dynamic (runtime) type (class) Child
. Which implementation of an instance (virtual) method is chosen is decided based on the runtime class. But whether you are allowed to call a method is decided based on the static type.