Concepts / Polymorphism

Polymorphism

Polymorphism allows a subtype to be treated as an instance of its parent type, enabling flexible code that works with multiple subtypes without type checking.

  • Programming

One Count for Everyone

Imagine counting everyone in a school building. You could write separate logic for teachers, students, and administrators. Polymorphism offers a different approach: treat each person as a SchoolMember and use one general operation for everyone. The code does not need to know which specific subtype it received.

Definition

Polymorphism allows a subtype to be treated as an instance of its parent type. This enables flexible code that works with multiple subtypes without checking each object's specific type.

SchoolMemberparent typeTeachersubtype objectStudentsubtype objectAdministratorsubtype objecttreated astreated astreated as
How can objects from different subtypes be used wherever a SchoolMember object is expected?

Runtime Method Selection

Polymorphism becomes especially useful when a parent class defines an operation that subtypes can provide in their own way. Suppose SchoolMember has a method named tell(), and Teacher and Student are subtypes. Code can work with a SchoolMember reference and call tell() without first checking whether the object is a Teacher or a Student.

Dynamic dispatch determines which method runs at runtime from the object's actual subtype. If a variable is treated as a SchoolMember but the object it refers to is a Teacher, calling tell() runs the Teacher version of tell(), not the generic SchoolMember version. The reference type provides the parent-level view, while the actual object type determines the method implementation that executes.

SchoolMemberobjectsTeacher or Studenttell()same callTeacher tell()actual type: TeacherStudent tell()actual type: Studentcallruntime type is Teacherruntime type is Student
How does one piece of code process different subtype objects without checking each object's specific type?

Following the Object

Worked example

Choosing the Correct tell() Method

A variable is treated as a SchoolMember, but the object assigned to it is a Teacher. What happens when tell() is called?

  1. 1
    Start with the parent view

    The variable is treated as a SchoolMember, so general code can work with it through the parent type.

  2. 2
    Identify the actual object

    The object held by the variable is a Teacher, which is a subtype of SchoolMember.

  3. 3
    Dispatch at runtime

    Dynamic dispatch uses the actual object type to select the method implementation.

  4. 4
    Run the subtype method

    The Teacher version of tell() runs rather than the generic SchoolMember version.

Result

A parent-typed reference can lead to execution of the correct subtype method because runtime dispatch follows the actual object type.

The important separation is between how the object is treated and what the object really is. The parent type gives code a common way to work with different objects. Dynamic dispatch then preserves subtype-specific behavior when the operation is executed.

Inherited Functionality

Inheritance also makes shared functionality available across the subtype family. When functionality is added to the parent class, all of its subtypes automatically receive that functionality. For example, if a new ID card field is added to SchoolMember, both Teacher and Student objects have access to that field without either subtype needing a separate modification.

SchoolMemberID card fieldTeacherID card availableStudentID card availableinherited byinherited by
When functionality is added to the parent class, which subtypes receive it automatically?

Isolated Subtype Changes

The direction of a change matters. A functionality change made in SchoolMember propagates to its subtypes. A change made only in Teacher remains in Teacher; it does not alter Student or the SchoolMember parent. This isolation allows one subtype to gain specialized behavior without changing the other members of the subtype family.

SchoolMembershared functionalityTeacherexisting functionalitySchoolMembershared functionalityTeacherspecialized functionalityStudentexisting functionalityStudentexisting functionalityparent ofparent ofparent ofparent of
What changes when Teacher adds specialized functionality, and what remains unchanged in SchoolMember and Student?
Best practice

When reasoning about a change, ask where it was made. A parent-class change is shared by all subtypes. A subtype-only change stays localized to that subtype and does not affect its siblings or its parent.

Mistakes with Polymorphism

  • Common mistake

    Checking every object's specific subtype before using a shared operation

    What it looks like

    Handling Teacher objects separately, then Student objects separately, even though both can be treated as SchoolMember objects.

    Why it fails

    Polymorphism is intended to let code work with multiple subtypes through their parent type without type checking.

    Do this instead

    Use the common parent type for the shared operation and let runtime dispatch select the correct subtype method.

  • Common mistake

    Assuming the reference type determines the method that executes

    What it looks like

    Expecting a SchoolMember reference holding a Teacher object to run only the generic SchoolMember version of tell().

    Why it fails

    Dynamic dispatch selects the method at runtime from the actual object type.

    Do this instead

    Distinguish the parent type used by the code from the actual subtype of the object.

  • Common mistake

    Assuming a subtype change spreads to sibling subtypes

    What it looks like

    Expecting a change made in Teacher to also change Student.

    Why it fails

    Changes made in a subtype remain isolated and do not affect other subtypes or the parent class.

    Do this instead

    Place functionality in the parent when it should be shared, and place it in a subtype when it should remain specialized.

Extension without Rewriting

Polymorphism supports the Open-Closed Principle. Code can be open for extension because new subtypes can be added, while existing code can remain closed for modification because it already works through the parent type. The benefit is a uniform operation for a growing set of subtypes rather than a separate type-specific branch for every subtype.

MEDIUM

A school program needs to process both Teacher and Student objects using one general SchoolMember-based operation. Explain how polymorphism helps the program avoid checking each object's specific subtype, and describe which method should run when the actual object is a Teacher.

Hints
  • Start by identifying the parent type shared by both objects.
  • Separate the type used by the general code from the object's actual subtype.
  • Use dynamic dispatch to determine which subtype implementation runs.

Polymorphism in Practice

  1. 1
    Polymorphism lets a subtype be treated as its parent type, so one piece of code can work with multiple subtypes uniformly. Dynamic dispatch chooses the correct subtype method at runtime from the actual object type. Functionality added to a parent class becomes available to all subtypes, while functionality added only to one subtype remains isolated. Together, these properties let code support new subtypes without requiring existing code to be modified for every specific type.

Key Takeaways

  • A subtype can be treated as an instance of its parent type.
  • Dynamic dispatch selects the correct subtype method at runtime based on the actual object type.
  • Functionality added to a parent class automatically becomes available to its subtypes.
  • Changes made in one subtype remain isolated from the parent and sibling subtypes.
  • Polymorphism supports flexible code that can be extended with new subtypes without changing existing general logic.

Related concepts

More concepts starting with P