Overloading and overriding. Two concepts with names so similar you might wonder why they had to be.
They are common exam and interview topics, and their similar names are largely to blame for the confusion. Their mechanisms are completely different: one creates multiple functions with the same name, while the other redefines an inherited function.
They are resolved at different times, too: one at compile time and the other at runtime. This difference leads directly to the performance concepts of static and dynamic dispatch.
This article draws a clear line between them with Swift examples.
Here is the key summary.
- Overloading: Define multiple functions with the same name but different parameters. Unrelated to inheritance
- Overriding: A child redefines a parent method. Requires inheritance
- Overloading selects the function at compile time; overriding selects it at runtime
- Overriding is the core mechanism behind polymorphism
Overloading: One Name, Multiple Functions
Overloading means defining multiple functions with the same name but different parameter configurations—count, types, or labels.
func area(radius: Double) -> Double { .pi * radius * radius }
func area(width: Double, height: Double) -> Double { width * height }
func area(side: Double) -> Double { side * side }
The compiler examines the arguments at the call site to determine which function to use. The moment you write area(radius: 3), the first function is selected. It is decided before execution.
Think about C, which had no overloading, and you will appreciate it. The absolute-value function had different names by type: abs, labs, and fabs. Overloading lets concepts with the same meaning share a name.
Swift uses overloading throughout its standard library, in functions such as print(:) and min(:_:). Operator overloading also lets + handle integer addition, string concatenation, and array combination.
One caution: avoid overloads that differ only in their return type. Swift allows this syntactically in some cases, but without an explicit type at the call site, it causes an ambiguity error and confuses readers.
Overriding: Redefining the Inherited
Overriding means that a child class redefines a method inherited from its parent class with the same signature. An inheritance relationship is required.
class Animal {
func speak() { print("...") }
}
class Dog: Animal {
override func speak() { print("Woof") }
}
class Cat: Animal {
override func speak() { print("Meow") }
}
This is the key moment.
let animals: [Animal] = [Dog(), Cat()]
for animal in animals {
animal.speak() // Woof, meow
}
The variable type is Animal, but the method that runs belongs to the actual instance. Which speak to call is determined at runtime by looking at the real object. This is dynamic dispatch—the mechanism that makes polymorphism work.
It is also worth noting that Swift requires the override keyword. The compiler catches accidentally declaring a method with the same signature as a parent method or failing to override because of a typo. Conversely, adding final in the parent can prohibit overriding.
Compare Them at a Glance
| Category | Overloading | Overriding |
|---|---|---|
| Definition | Same name, different parameters | Redefine the same signature |
| Inheritance | Not required | Required |
| Resolution time | Compile time (static) | Runtime (dynamic) |
| Purpose | Name consistency, API convenience | Polymorphism, behavior replacement |
| Swift keyword | None | override (required); prohibited with final |
The difference in resolution time also affects performance. A call fixed at compile time (static dispatch) can jump directly, while a runtime decision (dynamic dispatch) must go through the actual type’s method table. In Swift, marking declarations final or private gives the compiler an opportunity to convert dynamic dispatch to static dispatch and optimize it.
A Mnemonic That Won’t Confuse You
Remember the words literally.
Overload = load too much. You “load” multiple functions onto the same name. One name, multiple behaviors.
Override = ignore and step over. You “overwrite” the parent definition. One definition, replaced behavior.
You can start an interview answer like this.
“Overloading places multiple functions with the same name but different parameters, and is resolved at compile time. Overriding redefines an inherited method, and is resolved at runtime based on the actual type. Overriding is what enables polymorphism.”
Summary
- Overloading: Define multiple functions with the same name and different parameter configurations. No inheritance required
- Overriding: A child redefines a parent method with the same signature. Inheritance required
- Overloading resolves the call target at compile time (static); overriding resolves it at runtime (dynamic)
- The core mechanism of polymorphism is overriding and dynamic dispatch
- Swift prevents mistakes by requiring the override keyword, and final can prohibit overriding
- Mnemonic: Overload loads multiple behaviors onto a name; Override overwrites a definition

