swift-err is a Swift package that provides convenient error handling macros for Swift projects, allowing for more expressive and type-safe error handling.
@err
function macro to access thrown errors in guard else statements@err_traced
includes trace information in thrown errors (file, line, function)- Works with any function that can throw, including async functions
@err
func throwsExample() throws async -> String {
guard let result = try await someThrowingFunction() else {
throw err // "err" is the error thrown by someThrowingFunction
}
return result
}
@err
func resultExample() async -> Result<String, Error> {
guard let result = await someResultFunction().get() else {
return .failure(err) // "err" is the error thrown by someResultFunction
}
return .success(result)
}
Add the following dependency to your Package.swift
file:
.package(url: "https://github.com/walteh/swift-err.git", branch: "main")
Then, add "Err" to your target's dependencies:
.target(name: "YourTarget", dependencies: ["Err"]),
Use the @err
macro to simplify error handling in your functions:
// Without @err macro
func resultWithoutErrMacro() async -> Result<String, Error> {
guard let res = try? await myThrowingAsyncFunc(12) else {
// ⚠️ We have no idea what the error is
return .failure(UnknownError())
}
return .success("\(res)")
}
// With @err macro
@err
func resultWithErrMacro() async -> Result<String, Error> {
guard let res = try await myThrowingAsyncFunc(12) else {
// ✅ "err" is the error thrown by myThrowingAsyncFunc
switch err {
case is ValidBusinessError:
return .success("operation already completed")
default:
return .failure(err) // or "throw err" if you want to rethrow
}
}
return .success("\(res)")
}
For more detailed error tracing, use the @err_traced
macro. This wraps the error with the location (file, line, and function) where the error was triggered.
@err_traced
func tracedExample() throws -> String {
guard let result = try someThrowingFunction() else {
throw err // This error will include trace information
}
return result
}
The @err
and @err_traced
macros expand to code that captures the error from throwing expressions. Here's a simplified view of what the macro expansion looks like:
// Original code with @err macro
@err
func example() throws -> String {
guard let result = try someThrowingFunction() else {
throw err
}
return result
}
func example() throws -> String {
guard let result = someResultFunction().get() else {
throw err
}
return result
}
// Expanded code (simplified)
func example() throws -> String {
var ___err: Error? = nil
guard let result = Result.___err___create(catching: {
try someThrowingFunction()
}).___to(&___err) else {
let err = ___err!
throw err
}
return result
}
This expansion allows you to use err
in your guard statements to access the thrown error, enabling more expressive error handling.
The package includes comprehensive unit tests. Run the tests using:
swift test
- Swift 6.0+
This project is licensed under the Apache License 2.0.
Contributions are welcome! Please feel free to submit a Pull Request.