Intro to iOS Development
  • Welcome
    • ☀️Introduction
    • 🐣Getting Started
    • 🐦Course Staff
  • Logistics
    • 📜Syllabus
    • 🗓️Schedule
    • 🖊️Grading
    • 🙋‍♂️Office Hours
    • Ed Discussion
  • Assignments
    • 🍼A1: Swift Basics
    • 🧑A2: Profile
    • 💬A3: ChatDev
    • 👨‍🍳A4: ChefOS
    • 👨‍🍳A4: ChefOS - SwiftUI
    • 📱Hack Challenge
      • 🏆FA23 Winners
  • Lectures
    • 1️⃣Logistics + Swift Basics
    • 2️⃣UIKit + AutoLayout
  • 3️⃣MVC + Navigation + Delegation
  • 4️⃣UITableView
  • 5️⃣UICollectionView
  • 6️⃣Networking I
  • 7️⃣Networking II
  • 8️⃣SwiftUI I
  • 9️⃣SwiftUI II
  • 🔟Persistence + SnapKit
  • 🔔(11) Notifications
  • 🌎(12) Deployment and MapKit
  • Chapters
    • 🖐️Introduction
    • ☁️Git + GitHub
      • 1️⃣Git Installation
      • 2️⃣Git Basics
      • ➕Git+
    • 🐣Swift Basics
      • 1️⃣Variables and Constants
      • 2️⃣Data Types
      • 3️⃣Operators
      • 4️⃣Data Structures
      • 5️⃣Conditionals
      • 6️⃣Loops
      • 7️⃣Functions
      • 8️⃣Closures
      • 9️⃣Optionals
    • 🧰UIKit + AutoLayout
      • 1️⃣Classes
      • 2️⃣UIKit
      • 3️⃣AutoLayout
    • 📺MVC + Navigation + Delegation
      • 1️⃣MVC
      • 2️⃣Navigation
      • 3️⃣Delegation
    • 🏓UITableView
      • 1️⃣What is a UITableView?
      • 2️⃣UITableView Setup
    • 📚UICollectionView
      • 1️⃣What is a UICollectionView?
      • 2️⃣UICollectionView Setup
    • 🌐Networking I
      • 1️⃣HTTP Requests
      • 2️⃣Callbacks
      • 3️⃣Codable
    • 🌍Networking II
      • 1️⃣Alamofire
      • 2️⃣GET Requests
      • 3️⃣POST Requests
      • 4️⃣URLSession
    • 💾Persistence + SnapKit
      • 1️⃣Persistence
      • 2️⃣SnapKit
    • 🕊️SwiftUI
      • 1️⃣Introduction to SwiftUI
      • 2️⃣Getting Started with SwiftUI
      • 3️⃣Views + Modifiers
      • 4️⃣Layouts
      • 5️⃣Navigation
      • 6️⃣Property Wrappers
    • 🎛️Widgets
      • 1️⃣Introduction to Widgets
      • 2️⃣Setting Up Widgets
      • 3️⃣Building Widgets
      • 4️⃣Configuring Widgets
    • 🧱Project Foundation
    • ✅Testing
      • 1️⃣Unit Testing
    • 👣Debugging
      • 1️⃣OSLog
      • 2️⃣Crashlytics
      • 3️⃣Analytics
    • ☁️CI/CD
      • 1️⃣Xcode Cloud
      • 2️⃣AppStore Shipping
  • Guides
    • 🔨Xcode Project Setup
    • 🎨Figma
    • 📬Postman
    • 🥥CocoaPods
    • 🧰UIKit Handbook
    • 📑Tab Views
      • UITabBarController
      • TabView
  • Work in progress
    • 🧵Concurrency
    • 2️⃣UI Testing
    • 🕐Reactive Programming
    • 🧠Memory Management
      • 🔁ARC
    • 📦Storage
    • 📣Notifications
  • Archived
    • SP24
      • Logistics
        • 📜Syllabus
        • 🗓️Schedule
        • 🖊️Grading
        • 🙋‍♂️Office Hours
      • Assignments
        • 🍼A1: Swift Basics
        • 🧑A2: Profile
        • 💬A3: ChatDev
        • 👨‍🍳A4: ChefOS
        • 📱Hack Challenge
          • 🏆FA23 Winners
      • Lecture
        • 0️⃣Course Intro + Logistics + Git Setup
        • 1️⃣Swift Basics
        • 2️⃣UIKit + AutoLayout
        • 3️⃣MVC + Navigation + Delegation
        • 4️⃣UITableView
        • 5️⃣UICollectionView
        • 6️⃣Networking I
        • 7️⃣Networking II
        • 8️⃣Persistence + SnapKit
        • 🔟SwiftUI
        • 🔢TabViews
    • FA23
      • Logistics
        • 🐣Getting Started
        • 🐦Course Staff
        • 📜Syllabus
        • 🗓️Schedule
        • 🖊️Grading
        • 🙋‍♂️Office Hours
      • Assignments
        • 🍼A1: Swift Basics
        • 🧑A2: Profile
        • 💬A3: ChatDev
        • 👨‍🍳A4: ChefOS
        • 📱Hack Challenge
          • 🏆FA23 Winners
      • Lectures
        • 0️⃣Course Intro + Logistics
        • 1️⃣Swift Basics
        • 2️⃣UIKit + AutoLayout
        • 3️⃣MVC + Navigation + Delegation
        • 4️⃣UITableView
        • 5️⃣UICollectionView
        • 6️⃣Networking I
        • 7️⃣Networking II
        • 8️⃣Persistence + SnapKit
        • 🎛️Widgets
          • 👼Introduction to Widgets
          • ⚒️Setting Up Widgets
          • 🧱Building Widgets
          • 👨‍💻Configuring Widgets
        • 🔟SwiftUI
    • SP23
      • Logistics
        • Lecture Schedule
        • Syllabus
        • Grading
        • SP23 Office Hours
      • Chapters
        • 1. Intro to Swift & Xcode
          • Lecture Handout
          • Lecture Demo
          • 🍼Project: Swift Basics
        • 2. UIKit and AutoLayout
          • Lecture Handout
          • Lecture Demo
          • 🛒Project: UIKit + AutoLayout
        • 3. Navigation, MVC, and Delegation
          • Lecture Handout
          • Lecture Demo
          • Project: Navigation + Delegation
        • 4. UITableView
          • Lecture Handout
          • Lecture Demo
          • Project: UITableView
        • 5. UICollectionView
          • Lecture Handout
          • Lecture Demo
          • Project: UICollectionView
        • 6. Networking I
          • Lecture Handout
          • Lecture Demo
          • Project: Persistence
        • 7. Networking II
          • Lecture Handout
          • Lecture Demo
            • Message Board
          • Project: Networking II
        • 8. Swift UI
        • 9. CocoaPods
          • 🍫Lecture Handout
          • 🧑‍🍳Lecture Demo
      • Cheat Sheets
        • Setting Up a New Xcode Project
        • Submitting Your Projects
        • Setting Up CocoaPods
    • 2022
      • SwiftUI
    • 2021
      • Adding Flare
      • Project: UIView Animations (Optional - Extra Credit)
      • UIView Animations
      • Xcode Tips and Tricks
    • 2019
      • Firebase
      • Persistence: UserDefaults
  • Swift Guide (ARCHIVED)
    • About this Textbook
    • Documentation
    • Constants and Variables
      • Variable Properties
      • Lazy and Static Variables
    • Functions
    • Ranges
    • Arrays
      • Basic Array Operations
      • Iteration and Enumeration
      • Advanced Array Operations
    • Tuples
    • Conditions and While Loops
    • For Loops
    • Enums and Switches
      • Enums with Associated Values
      • Indirect Enums
    • Classes and Structs
    • Optionals
    • Dictionaries
      • Dictionary Implementation
    • Closures
    • Constraints
    • Generics
    • Protocols
      • Protocols With Associated Types
    • Casting
    • Errors
    • Networking
      • Result
    • Inout
Powered by GitBook
On this page

Was this helpful?

Export as PDF
  1. Swift Guide (ARCHIVED)
  2. Enums and Switches

Indirect Enums

Credits to the great wonderful amazing Daniel Vebman for introducing me to the topic

Indirect Enums are the most functional of types. For this entry, I will be assuming you have already or are currently taking 3110. Let's get into things!

Ever wanted to make natural numbers in Swift? Neither have I, but here's how to do it. As a quick refresher, here's the OCaml version:

type Nat = 
| Zero
| Succ of Nat

Hopefully, this rings a bell. 3 would be Succ (Succ (Succ Zero)).

In Swift, ideally you could do:

enum Nat {
    case zero
    case succ(Nat)
}

Sadly, this does not compile: "Recursive enum 'Nat' is not marked 'indirect'".

A little look into what's going on here: types like enums and structs require that memory size is known at compile time. With recursion, it has no clue what the size is. As it suggests, we can use the keyword indirect to circumvent this:

enum Nat {
    case zero
    indirect case succ(Nat)
}

indirect enum Nat {
    case zero
    case succ(Nat)
}

Both of the above Nat's are valid. Making an entire enum indirect makes all of the cases indirect, but you can also make individual cases indirect. Alright, well let's start building this thing out!

First, let's create some functions to help us create and analyze Nats:

var value: Int {
    get {
        switch self {
            case .zero: return 0
            case let .succ(sub): return 1 + sub.count
        }
    }
}

static func fromInt(_ int: Int) -> Nat {
    assert(int >= 0)
    if int == 0 {
        return .zero
    } else {
        return .succ(fromInt(int - 1))
    }
} 

Time to test!

for i in 0...100 {
    assert(i == Nat.fromInt(i).count)
}
// And one more
let x: Nat = .succ(.succ(.succ(.zero)))
assert(x.count == 3)

Great those passed! Let's work on adding some operators. I'll start off with an important one for code: ++ that Swift happens to lack:

static postfix func ++ (lhs: inout Nat) {
    lhs = .succ(lhs)
}

Now, this is some dang cool Swift! We're really cooking :) Let's test before we get ahead of ourselves:

var x = Nat.fromInt(3)
x++
x.count
// 4: Int

I'll stop babying you for the rest. Try it out! Have some fun!

I implemented +, -, and *.

Here's my code:

indirect enum Nat {
    case zero
    case succ(Nat)

    static postfix func ++ (lhs: inout Nat) {
        lhs = .succ(lhs)
    }

    var count: Int {
        get {
            switch self {
            case .zero: return 0
            case let .succ(sub): return 1 + sub.count
            }
        }
    }

    static func + (_ lhs: Nat, _ rhs: Nat) -> Nat {
        switch lhs {
        case .zero: return rhs
        case let .succ(sub): return sub + .succ(rhs)
        }
    }

    static func - (_ lhs: Nat, _ rhs: Nat) -> Nat {
        switch (lhs, rhs) {
        case (.zero, _), (_, .zero): return lhs
        case let (.succ(sub), .succ(remaining)): return sub - remaining
        }
    }

    static func * (_ lhs: Nat, _ rhs: Nat) -> Nat {
        switch lhs {
        case .zero: return .zero
        case let .succ(sub): return (sub * rhs) + rhs
        }
    }

    static func fromInt(_ int: Int) -> Nat {
        assert(int >= 0)
        if int == 0 {
            return .zero
        } else {
            return .succ(fromInt(int - 1))
        }
    }
}

// Construction Tests
for i in 0...100 {
    assert(i == Nat.fromInt(i).count)
}
// And one more
let x: Nat = .succ(.succ(.succ(.Zero)))
assert(x.count == 3)

// Random tests
for _ in 0...100 {
    let a = Int.random(in: 0...10)
    let b = Int.random(in: 0...10)
    let A = Nat.fromInt(a)
    let B = Nat.fromInt(b)
    assert(a + b == (A + B).count)
    assert(max(a - b, 0) == (A - B).count)
    assert(a * b == (A * B).count)
}

print("done")

PreviousEnums with Associated ValuesNextClasses and Structs

Last updated 3 years ago

Was this helpful?