Errors are typically modeled as an enum conforming to the Error protocol, with cases representing each distinct failure. A function that might throw is marked throws in its signature — REQUIRED, and compiler-enforced, unlike Kotlin's total absence of any such declaration — though unlike Java's checked exceptions, plain throws doesn't specify which Error types are possible, only that some error might occur — Swift 6's typed throws (throws(SomeError), SE-0413) is the opt-in exception: it lets a function declare the single specific error type it throws, giving catch blocks a concretely-typed error instead of the general Error protocol. Callers must handle this explicitly: do/catch with try inside the do block, try? converting a thrown error into nil instead of propagating it, or try! asserting no error will occur (crashing at runtime if that assertion turns out wrong).
Defining errors and a throwing function
throws is REQUIRED on divide's signature — omitting it while the body still contains a throw statement is a compile error, unlike Kotlin, where no such declaration exists at all.
enum MathError: Error {
case divideByZero
}
func divide(_ a: Int, by b: Int) throws -> Int { // 'throws' is REQUIRED here
if b == 0 {
throw MathError.divideByZero
}
return a / b
}do/catch: handling the thrown error
try marks each call inside the do block that might throw — execution jumps to a matching catch the instant an error is actually thrown, exactly like a typical try/catch elsewhere.
do {
let result = try divide(10, by: 0)
print(result)
} catch MathError.divideByZero {
print("Cannot divide by zero")
} catch {
print("Unknown error: \(error)")
}try? and try!: two alternatives to do/catch
try? converts a thrown error into nil instead of propagating it — genuinely useful when the caller only cares whether it succeeded, not why it failed; try! is a much stronger assertion, crashing the program at runtime if an error actually occurs.
let result1 = try? divide(10, by: 0) // nil — the error becomes an Optional instead
print(result1) // nil
// let result2 = try! divide(10, by: 0) // CRASHES at runtime — asserting no error will happen