ProgramGuru

Inheritance, overrides and safe casts

Inheritance, overrides and safe casts

A school has a general person description and a specialized teacher description. Class inheritance can express a specialization, and an override replaces an inherited implementation. It should model a genuine substitutable relationship rather than merely avoid copying a few lines.

What you’ll learn

  • Trace an override through a base reference.
  • Handle a mismatched safe cast.

Inheritance, overrides and safe casts in the example

  1. Superclass reference

    A school has a general person description and a specialized teacher description.

    Superclass reference
  2. Subclass instance

    Kotlin classes and members are final by default.

    Subclass instance
  3. Overridden behaviour

    The reference’s declared type is Person, but its instance is Teacher.

    Overridden behaviour
The reference’s declared type is Person, but its instance is Teacher. The override supplies Teacher at runtime, the is check succeeds and the safe cast allows the same role call.

Understand inheritance, overrides and safe casts

Kotlin classes and members are final by default. Mark a class and overridable member open when specialization is intended, and use override in the subclass. A safe cast with as? returns null on a mismatch, while an unchecked as can fail. Is checks type membership and can enable a smart cast.

Follow inheritance, overrides and safe casts

Save the complete source as Main.kt and use the Kotlin/JVM environment. No separate input file is needed.

Kotlin/JVM · complete program

open class Person {
  open fun role(): String = "Person"
}
class Teacher : Person() {
  override fun role(): String = "Teacher"
}
fun main() {
  val person: Person = Teacher()
  println(person.role())
  println(person is Teacher)
  println((person as? Teacher)?.role() ?: "Other")
}

Expected output

Teacher
true
Teacher

Follow the execution

The reference’s declared type is Person, but its instance is Teacher. The override supplies Teacher at runtime, the is check succeeds and the safe cast allows the same role call.

Try this in the Kotlin compiler by pasting the complete program.

Practice: Inheritance, overrides and safe casts

Your task: What does as? Teacher produce for an ordinary Person instance?

Kotlin/JVM · complete program

open class Person {
  open fun role(): String = "Person"
}
class Teacher : Person() {
  override fun role(): String = "Teacher"
}
fun main() {
  val person: Person = Teacher()
  println(person.role())
  println(person is Teacher)
  println((person as? Teacher)?.role() ?: "Other")
}

Worked answer

It returns null. A safe cast checks the existing instance rather than creating a teacher.

Inheritance, overrides and safe casts: the important boundary

Inheritance should express a substitutable relationship, not merely reuse a few lines. Prefer an interface or composition for unrelated capabilities. Do not assume Java’s or Swift’s default overridability rules apply.

Check your understanding

What does as? Teacher produce for an ordinary Person instance?
Choose one answer. You can try again.

Answer and explanation

It returns null.

It returns null. A safe cast checks the existing instance rather than creating a teacher.

Inheritance, overrides and safe casts: what to keep in mind

It returns null. A safe cast checks the existing instance rather than creating a teacher. Inheritance should express a substitutable relationship, not merely reuse a few lines.

Further reading: official Kotlin documentation for this topic.

Reaching the recap and completing the quizzes are separate milestones.

    Next lesson: Interfaces and delegation →