What is Polymorphism?
Polymorphism is a core concept in object‑oriented programming that allows objects of different types to respond to the same method call in their own way. The word comes from Greek meaning 'many forms'. In Dart, polymorphism enables you to write more flexible and reusable code by treating objects of different classes through a common interface.
Types of Polymorphism
Polymorphism is generally divided into two categories:
- Compile‑time polymorphism (static binding) – achieved through method overloading or operator overloading. However, Dart does not support traditional method overloading based on different parameter lists. Instead, you can use optional parameters or named parameters to simulate similar behaviour.
- Runtime polymorphism (dynamic binding) – achieved through method overriding, where a subclass provides its own implementation of a method defined in its superclass. This is the primary form of polymorphism in Dart.
Polymorphism through Inheritance (Method Overriding)
When a subclass overrides a method from its superclass, you can call that method on a variable of the superclass type that actually holds an instance of the subclass. At runtime, Dart determines which method to invoke based on the actual object type – this is called dynamic dispatch.
In this example, myPet is declared as an Animal, but at runtime it refers to a Dog and then a Cat. The appropriate speak() method is called each time.
Polymorphism with Interfaces (Implicit Interfaces)
Every class in Dart implicitly defines an interface containing all its instance members. A class can implement one or more interfaces, which forces it to provide concrete implementations of those members. This allows different classes to be used interchangeably through the interface type.
The is and as Operators for Type Checking and Casting
Sometimes you need to check the actual type of an object at runtime. Use is (or is!) to test the type, and as to cast to a more specific type.
The covariant Keyword
When overriding a method, you can use the covariant keyword to narrow the type of a parameter. This tells Dart that the override accepts a more specific subtype of the original parameter type.
Polymorphism with dynamic (Use with Caution)
Dart's dynamic type disables static type checking, allowing any method call. This is a form of polymorphism, but it sacrifices type safety. Prefer using interfaces or inheritance instead.
Polymorphism with Generics
Generics allow you to write code that works with a variety of types while preserving type safety. For example, a List<T> can hold any type, but you still get static checking when you use it.
Key Takeaways
- Polymorphism allows objects of different types to be treated uniformly through a common interface.
- In Dart, the main form of polymorphism is runtime polymorphism achieved by overriding methods.
- Dart does not support traditional method overloading; use optional/named parameters instead.
- Use
implementsto enforce interface contracts and achieve polymorphism across unrelated classes.
- Use
- The
isandasoperators help with type checking and casting.
- The
covariantlets you narrow parameter types in overrides.
- Prefer using explicit interfaces over
dynamicfor type safety.
- Prefer using explicit interfaces over