SwSwift · Lesson 4 of 8

Structs, Enums & Value Types

Swift's twist on OOP: structs (copied on assignment) are the default, classes (shared references) the exception. And Swift enums carry data — they're a superpower, not a list of constants.

Swift
struct Student {
    let name: String
    var grade: Int = 0

    // Methods live inside; mutating ones must say so:
    mutating func improve(by points: Int) {
        grade += points
    }

    var letterGrade: String {        // computed property
        switch grade {
        case 90...: return "A"
        case 80...: return "B"
        default:    return "C"
        }
    }
}

var ada = Student(name: "Ada", grade: 88)   // free memberwise init
ada.improve(by: 7)
print(ada.letterGrade)      // A

// Value semantics — assignment copies:
var copy = ada
copy.grade = 0
print(ada.grade)            // still 95
Swift
// Enums with associated values — model 'one of N shapes':
enum NetworkResult {
    case success(data: String)
    case failure(code: Int, message: String)
    case offline
}

func handle(_ result: NetworkResult) {
    switch result {
    case .success(let data):
        print("got \(data)")
    case .failure(let code, let message):
        print("error \(code): \(message)")
    case .offline:
        print("no connection")
    }
}

handle(.failure(code: 404, message: "not found"))

// This is how Swift's own Optional works — it's just:
// enum Optional<T> { case some(T); case none }

Classes exist too (class Student { }) with inheritance and reference semantics — SwiftUI and most modern Swift use them sparingly. Protocols (Swift's interfaces) plus structs cover most designs: define capabilities as protocols, adopt them in small value types.

Swift
protocol Describable {
    var description: String { get }
}

struct Circle: Describable {
    let radius: Double
    var description: String { "circle r=\(radius)" }
}

// Protocol extensions give default behavior to all adopters:
extension Describable {
    func shout() -> String { description.uppercased() }
}
print(Circle(radius: 2).shout())    // CIRCLE R=2.0