Lesson 39Functions

Nested Functions

Functions Inside Functions

Nested functions are defined inside other functions. They're hidden from outside code and can access variables from their parent function!

Key Features

Encapsulation

Hidden from outside code

Closure Over Variables

Access outer scope

Can Be Returned

Create function factories

Organization

Group related helpers

Capturing Values

Nested functions can "capture" variables from their enclosing function. They remember these values even after the outer function returns!

When to Use

  • Helper functions only used in one place
  • Breaking up complex logic
  • Creating function factories
  • When you need to capture state
main.swift
// NESTED FUNCTIONS
// Functions defined inside other functions

func outerFunction() {
    print("Outer function called")

    func innerFunction() {
        print("Inner function called")
    }

    innerFunction()  // Call inner from outer
}

outerFunction()
// innerFunction()  // ERROR! Not accessible outside

// WHY USE NESTED FUNCTIONS?
// 1. Encapsulation - hide helper functions
// 2. Access to outer function's variables
// 3. Organize complex logic

// ACCESS TO OUTER VARIABLES
func countdown(from start: Int) {
    var current = start

    func step() {
        current -= 1
        print(current)
    }

    while current > 0 {
        step()  // Uses and modifies 'current'
    }
}

countdown(from: 5)
// 4, 3, 2, 1, 0

// RETURNING NESTED FUNCTIONS
func makeCounter() -> () -> Int {
    var count = 0

    func increment() -> Int {
        count += 1
        return count
    }

    return increment
}

let counter1 = makeCounter()
print(counter1())  // 1
print(counter1())  // 2
print(counter1())  // 3

let counter2 = makeCounter()  // New counter!
print(counter2())  // 1

// PRACTICAL EXAMPLE: Step-by-step calculation
func calculateTax(on amount: Double, rate: Double) -> Double {

    func applyRate() -> Double {
        return amount * rate
    }

    func roundToTwoDecimals(_ value: Double) -> Double {
        return (value * 100).rounded() / 100
    }

    let tax = applyRate()
    return roundToTwoDecimals(tax)
}

print(calculateTax(on: 99.99, rate: 0.07))  // 7.0

// MULTIPLE LEVELS OF NESTING
func level1() {
    func level2() {
        func level3() {
            print("Deeply nested!")
        }
        level3()
    }
    level2()
}

// CHOOSER PATTERN
func makeOperator(add: Bool) -> (Int, Int) -> Int {
    func addNumbers(_ a: Int, _ b: Int) -> Int {
        return a + b
    }

    func subtractNumbers(_ a: Int, _ b: Int) -> Int {
        return a - b
    }

    return add ? addNumbers : subtractNumbers
}

let operation = makeOperator(add: true)
print(operation(10, 5))  // 15

Try It Yourself!

Create a `makeMultiplier(by: Int)` function that returns a function to multiply numbers by that value!