0Pricing
Swift Academy · Lesson

Optimising Hot Paths: COW, Inlining and Specialisation

Applying @inline, @_specialize and value-type optimisations based on profiler data.

Optimising Hot Paths: COW, Inlining and Specialisation is a free Swift Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Swift Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Identify Before Optimising

Always profile first. Optimise only code that the Time Profiler identifies as a hot path — premature optimisation wastes time.

// Measure → Identify → Optimise → Re-measure
// A 10ms function called once is less important than
// a 0.1ms function called 10,000 times per frame

Copy-on-Write (COW)

Swift value types (Array, Dictionary) use COW: storage is shared until a mutation occurs, avoiding unnecessary copies.

var a = [1, 2, 3, 4, 5]
var b = a         // no copy yet, shared buffer
b.append(6)       // copy happens here (b mutates)
print(a.count)    // 5 — a unchanged

Ensuring COW in Custom Types

Implement COW in custom value types by wrapping mutable state in a reference type and copying before mutation.

struct Matrix {
  private class Storage { var data: [[Double]] }
  private var storage = Storage()
  private mutating func ensureUnique() {
    if !isKnownUniquelyReferenced(&storage) {
      storage = Storage(data: storage.data)  // copy on write
    }
  }
  mutating func set(row: Int, col: Int, value: Double) {
    ensureUnique()
    storage.data[row][col] = value
  }
}

@inline(__always)

Force the compiler to inline a function at every call site, eliminating call overhead for tiny functions called in tight loops.

@inline(__always)
func clamp(_ value: Float, _ min: Float, _ max: Float) -> Float {
  return Swift.max(min, Swift.min(max, value))
}

@inline(never)

Prevent inlining to reduce code size or force the compiler to treat a path as cold (rare).

@inline(never)
func handleUnexpectedError(_ error: Error) {
  // Large error-handling block — never inline to keep hot path small
}

@_specialize for Generics

Instruct the compiler to emit a specialized copy of a generic function for a specific type, enabling static dispatch and SIMD optimisations.

@_specialize(where T == Float)
@_specialize(where T == Double)
func normalize<T: FloatingPoint>(_ values: [T]) -> [T] {
  let max = values.max()!
  return values.map { $0 / max }
}

Whole-Module Optimization

WMO (enabled in Release) allows the compiler to inline and specialise across file boundaries within a module.

// Xcode: Build Settings → Swift Compiler → Code Generation
// Optimization Level: Optimize for Speed (-O)
// Compilation Mode: Whole Module
// Enables cross-file inlining and dead code elimination

Avoiding ARC Overhead

Frequent reference type creation in hot paths causes ARC retain/release overhead. Prefer value types or cache references.

// HOT PATH:
for _ in 0..<1_000_000 {
  let obj = HeavyClass()  // alloc + dealloc + ARC overhead
}
// BETTER: allocate once outside the loop
let obj = HeavyClass()
for _ in 0..<1_000_000 { obj.process() }

Using ContiguousArray

ContiguousArray guarantees contiguous storage (unlike Array for class elements), improving cache performance in tight loops.

var nums = ContiguousArray<Float>(repeating: 0, count: 10_000)
// Faster iteration than Array<Float> for bridged-to-ObjC types

Reducing Protocol Witness Table Lookups

Protocol dynamic dispatch uses witness tables. Generics + specialization replaces witness table lookups with direct calls.

// Dynamic dispatch (slower for hot path):
func process(_ drawable: any Drawable) { drawable.draw() }
// Static dispatch after specialization:
func process<T: Drawable>(_ drawable: T) { drawable.draw() }
// Compiler may devirtualize and inline

Benchmark with XCTMeasure

Always validate optimisations with XCTMeasure benchmarks in your test suite to prevent regressions.

func testNormalizePerformance() {
  let data = Array(0..<100_000).map { Float($0) }
  measure {
    _ = normalize(data)
  }
}

Quick Check

What does isKnownUniquelyReferenced(_:) check when implementing Copy-on-Write?

Lesson Recap

Profile first with Instruments. Rely on Swift's built-in COW for collections; implement it in custom value types with isKnownUniquelyReferenced. Use @inline(__always) for tiny hot-path functions, @_specialize for generic hotspots, and enable WMO in Release builds. Validate every optimization with XCTMeasure benchmarks.

Frequently asked questions

Is the “Optimising Hot Paths: COW, Inlining and Specialisation” lesson free?

Yes — the full text of “Optimising Hot Paths: COW, Inlining and Specialisation” is free to read here on the web, and the Swift Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Swift Academy course, upgrade to CoddyKit PRO.

What will I learn in “Optimising Hot Paths: COW, Inlining and Specialisation”?

Applying @inline, @_specialize and value-type optimisations based on profiler data. You practise Swift Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Swift Academy?

No prior experience is required. Swift Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Optimising Hot Paths: COW, Inlining and Specialisation” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Swift Academy lesson?

Yes. Every Swift Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Instruments Basics: Time Profiler
  2. Allocations and Leaks Instruments
  3. Main Thread Checker and Hangs
  4. Optimising Hot Paths: COW, Inlining and Specialisation
← Back to Swift Academy