Polymorphism: One Operation, Different Implementations

Display different records through one operation

A school report includes attendance and marks summaries. The report should ask each summary for descriptive text without hard-coding every summary type.

Polymorphism lets different values respond to a common operation with their own implementations. The caller depends on a compatible behavior contract.

  1. Identify the common operation

    Find the shared method the caller uses.

  2. Trace the receiver

    Explain why different objects return different text.

  3. Check compatibility

    Recognize that a matching name alone is not a matching contract.

One report call, different summary text

  1. Attendance summary

    Implements a text-producing describe method.

    Present: 28
  2. Marks summary

    Implements the same operation for marks.

    Total: 75
  3. Report loop

    Calls describe on either receiver.

    Common interface
Read these stages alongside the complete example. They explain the relationship; they do not execute code.

The caller asks for behavior rather than a type label

If each summary promises describe() returning a string, the caller can invoke that operation without checking its class. JavaScript permits this kind of structural use without a shared parent class.

This is often called duck typing: use the behavior a value supports. The metaphor is limited—real compatibility includes accepted arguments, returned meaning, side effects and failure behavior, not only a method name.

Before starting, review shared contracts and overriding. These examples use JavaScript; other languages can use different syntax and rules.

Read both summaries with the same call

Each object defines describe using method syntax. The loop calls the current object’s implementation, so two different strings are produced.

No branch checks “is this attendance?” The supported operation handles that distinction.

JavaScript · local teaching example

const summaries = [
  { describe() { return 'Present: 28'; } },
  { describe() { return 'Total: 75'; } }
];
for (const summary of summaries) {
  console.log(summary.describe());
}

Expected output

Present: 28
Total: 75

Add another compatible summary

A library summary can join the report without changing its loop, provided it returns descriptive text.

This is an extension of the interface contract, not proof that every arbitrary object belongs in the list.

JavaScript · local teaching example

const summaries = [
  { describe() { return 'Books borrowed: 2'; } }
];
for (const summary of summaries) console.log(summary.describe());

Expected output

Books borrowed: 2

Apply the rule to a small change

Add a trip summary returning “Trip confirmed” and display it through the same describe operation.

Worked answer

The report uses the unchanged method call. The new object supplies its own implementation, so extending the summaries does not require a new classification branch.

JavaScript · local teaching example

const summary = {
  describe() { return 'Trip confirmed'; }
};
console.log(summary.describe());

Expected output

Trip confirmed

Recognize mistakes and limits

An object with describe returning a Promise is not interchangeable with these synchronous string-returning objects unless the caller’s contract allows asynchronous results. Similar names can hide different behavior.

Method overloading and overriding are related terms but not identical to all forms of polymorphism. Language support varies. Avoid forcing unrelated objects into a vague method whose meaning changes from one receiver to another.

For the language or tool rules used here, see JavaScript class behavior.

Check the core idea

JavaScript · code for this question

const summaries = [
  { describe() { return 'Present: 28'; } },
  { describe() { return 'Total: 75'; } }
];
for (const summary of summaries) {
  console.log(summary.describe());
}
What lets the report use both objects without a type-specific branch?
Choose one answer. You can try again.

Answer and explanation

They both implement the promised describe operation.

Yes. The caller depends on compatible behavior.

Apply the idea to a new situation

Is a synchronous string result compatible with a Promise result automatically?
Choose one answer. You can try again.

Answer and explanation

No; the caller must be designed for that asynchronous contract.

Yes. Compatibility includes how the result is delivered.

Make the common behavior precise

Polymorphism lets one caller use several implementations through a compatible operation. Inheritance is one route, but JavaScript objects can support a shared contract without it.

Connect this idea with interface contracts and asynchronous result handling.

Reaching the recap and completing the quizzes are separate milestones.

    Next lesson: Constructors, Destructors and Resource Cleanup →