DevPrep

All topics › Object-oriented programming (OOP)

Subtype vs parametric polymorphism

Middle

Essence

These are two ways to write code that works with "different types through one interface", and in Swift they have different mechanics and cost.

Example

// Subtype polymorphism: a value of a subtype is used where the supertype
// is expected. Decided at runtime (vtable / witness table).
protocol Shape { func area() -> Double }
struct Circle: Shape { let r: Double; func area() -> Double { .pi * r * r } }
struct Square: Shape { let a: Double; func area() -> Double { a * a } }

let shapes: [any Shape] = [Circle(r: 1), Square(a: 2)]
let total = shapes.reduce(0) { $0 + $1.area() }   // existential, dynamic

// Parametric polymorphism: code is written once for any T; the compiler
// specializes it per concrete type (static dispatch, no boxing).
func totalArea<S: Shape>(_ shapes: [S]) -> Double {
    shapes.reduce(0) { $0 + $1.area() }
}
let circles = totalArea([Circle(r: 1), Circle(r: 2)])  // S == Circle

// `some Shape` = opaque type: parametric for the caller, one concrete type.
func makeShape() -> some Shape { Circle(r: 3) }

When to choose which

What the interviewer looks for

Practice this before your interview

DevPrep turns these answers into one-minute challenges: what does this code print, find the bug, mock interviews. One challenge a day.

Get DevPrep on the App Store