Programming languages · intermediate

Polymorphism and dispatch

Polymorphism lets one expression or interface work with values of multiple types. Dispatch is the mechanism that selects an applicable implementation, which can occur dynamically from a runtime receiver type, statically through overloading, or through other language-defined forms.

Why it matters

Polymorphism separates clients from concrete implementations, while dispatch rules determine which code actually runs. Precise distinctions prevent surprises involving overrides, overloads, generics, and substitutability.

Mental model

How to reason about polymorphism and dispatch

A call site states an operation through a contract. The language uses static types, runtime types, type arguments, or argument patterns to choose code according to a documented dispatch rule.

Analogy

Polymorphism is a common request form accepted by several specialist desks; dispatch is the routing rule that decides which desk handles this particular request.

Examples

See the boundary, not just the happy path

Worked example · Runtime receiver dispatch

Shape shape = new Circle(2); shape.area();

In Java, the overridden instance method selected for area is based on the runtime class Circle, while the static type Shape determines which members are valid at the call site.

Worked example · Parametric polymorphism

T first<T>(List<T> items) => items.first;

The Dart function works uniformly for many element types while preserving the relationship between input and output types. This is polymorphism without choosing among subclass method bodies.

Useful contrast · Overload selection can be static

print(int value) versus print(String value)

In languages with overloading, the compiler can select a signature using static argument types. That differs from dynamic dispatch of an overridden instance method.

Common mistakes

Misconceptions to remove early

Reducing all polymorphism to inheritance

Interfaces, structural typing, generics, protocols, traits, and ad-hoc overloads provide other forms. Inheritance is one possible mechanism, not the definition.

Ignoring behavioral substitutability

A subtype that satisfies method signatures but violates promised behavior can break callers. Useful polymorphism requires implementations to preserve the interface's semantic contract.

Quick check

Can you predict the result?

1. In a typical overridden Java instance call, what selects the method body?
  • The runtime class of the receiver, subject to Java's dispatch rules.
  • The variable name's spelling.
  • The order of files in the source directory.
Answer: The runtime class of the receiver, subject to Java's dispatch rules.
2. Why is a generic identity-like function polymorphic without subclass dispatch?
Answer: One parameterized implementation works uniformly across many type arguments.

Keep building

Authoritative references

Make the idea retrievable.

Study this concept with spaced repetition, next to the commands where you use it.

Get Terminaster