Throw and handle recoverable errors
Throw and handle recoverable errors
A score form can receive a number outside the accepted range. Recoverable failure should be expressed in the function’s contract so callers decide how to respond. A throwing function can produce a value or throw an error; do-catch handles that error at the call site.
What you’ll learn
- Throw a domain error and match it in catch.
- Distinguish try, try? and an unsafe forced-success assertion.
Throw and handle recoverable errors in the example
Validate range
A score form can receive a number outside the accepted range.
Validate rangeThrow on failure
An error type conforms to Error.
Throw on failureCatch and explain
Validation throws before returning a mark.
Catch and explain
How throw and handle recoverable errors works
An error type conforms to Error. Calling a throwing operation normally needs try, making possible failure visible. A catch block can match a specific case. try? converts failure into nil, while try! asserts no error will occur and can trap if that assertion is wrong.
Work through throw and handle recoverable errors
Save this complete program as main.swift and run it with the Swift toolchain. No separate input file is needed.
Swift · complete program
enum MarkError: Error { case outOfRange }
func validate(_ score: Int) throws -> Int {
guard (0...100).contains(score) else { throw MarkError.outOfRange }
return score
}
do {
print(try validate(120))
} catch MarkError.outOfRange {
print("Score must be 0...100")
} catch {
print("Unexpected error")
}Expected output
Score must be 0...100Follow the execution
Validation throws before returning a mark. Control leaves the do body and enters the specific catch, so no numeric score is printed. The final catch handles errors not covered by the earlier pattern.
Try this program in the Swift compiler. Paste the complete source above.
Practice: Throw and handle recoverable errors
Your task: What happens if validate receives 80 instead?
Swift · complete program
enum MarkError: Error { case outOfRange }
func validate(_ score: Int) throws -> Int {
guard (0...100).contains(score) else { throw MarkError.outOfRange }
return score
}
do {
print(try validate(120))
} catch MarkError.outOfRange {
print("Score must be 0...100")
} catch {
print("Unexpected error")
}Worked answer
It returns 80 and the print displays that value. Neither catch executes because no error was thrown.
Handle failure without forcing success
Defer schedules cleanup when the enclosing scope exits under normal language execution, including a throw. It does not make every failure recoverable or catch arbitrary process crashes. Use errors for expected failure paths with a response policy.
Check your decision
Handle failure without forcing success
It returns 80 and the print displays that value. Neither catch executes because no error was thrown. Defer schedules cleanup when the enclosing scope exits under normal language execution, including a throw.
Further reading: official Swift language guide.
Reaching the recap and completing the quizzes are separate milestones.