Swift Language Patterns
Apply modern Swift 6.3 syntax and idioms without altering behavior or evaluation order. Route concurrency to swift-concurrency, deep serialization to swift-codable, formatting to swift-formatstyle, naming to swift-api-design-guidelines, and SwiftUI state to swiftui-patterns.
Contents
- Expressions & Control Flow
- Typed Throws (Swift 6+)
- Opaque vs Existential Types
- Result Builders & Property Wrappers
- Modern Collections & Regex
- Common Mistakes
- Review Checklist
- References
Expressions & Control Flow
Use value-producing if and switch expressions for direct assignment, initialization, and single-expression returns:
// Direct variable initialization from expression
let statusColor = switch order.status {
case .pending: Color.orange
case .completed: Color.green
case .failed: Color.red
}
let badge = if isFeatured { "star.fill" } else { "circle" }
Every branch must produce identical value types without multi-statement bodies.
Typed Throws (Swift 6+)
Specify concrete error types when callers benefit from exhaustive compile-time error handling:
enum PaymentError: Error {
case cardExpired, insufficientFunds
}
func processPayment() throws(PaymentError) {
guard hasFunds else { throw .insufficientFunds }
}
// Caller error handling is exhaustive without casting
do {
try processPayment()
} catch {
switch error {
case .cardExpired: promptNewCard()
case .insufficientFunds: promptDeposit()
}
}
Use throws(Never) for non-throwing conformance in generic protocols. For mixed or open error sources, retain untyped throws.
Opaque vs Existential Types
some Protocol(Opaque): Preferred for return and parameter types. Preserves underlying static type information, enables compiler optimizations, and avoids existential container allocation overhead.any Protocol(Existential): Use only when dynamic heterogeneous collections or runtime polymorphism is explicitly required (e.g.[any Plugin]).
// Parameter pack / opaque parameter
func render(item: some Displayable) { ... }
// Heterogeneous collection requires existential boxing
let plugins: [any Plugin] = [AudioPlugin(), VisualPlugin()]
Result Builders & Property Wrappers
@resultBuilder: Construct declarative DSLs by implementingbuildBlock,buildOptional, andbuildEither.@propertyWrapper: Encapsulate reusable property storage or validation viawrappedValueand projectedprojectedValue($).
@propertyWrapper
struct Clamped<T: Comparable> {
var value: T
let range: ClosedRange<T>
var wrappedValue: T {
get { value }
set { value = min(max(newValue, range.lowerBound), range.upperBound) }
}
}
Modern Collections & Regex
- Use regex literals
#/pattern/#with typed capture groups andRegexBuilder. - Leverage Swift collection operations:
contains(where:),allSatisfy,min(by:), and non-mutating transformations.
Common Mistakes
- Defaulting to
anyinstead ofsome: Usingany Protocolincurs existential boxing costs and suppresses type relationship inference. Prefersome Protocol. - Overusing typed throws for general errors: Forcing
throws(MyError)on functions that wrap URLSession or system APIs requires fragile error translation. Use untypedthrowsfor mixed errors. - Multi-statement branches in expressions:
if/switchexpressions only evaluate single-expression branches. Multi-line logic requires traditional statements. - Forgetting parentheses in function calls: Wrap expression arguments in parentheses when passing to functions to avoid parsing ambiguity.
- Modifying evaluation order during refactoring: When modernizing with expressions, ensure parameter evaluation order remains strictly preserved.
Review Checklist
- Value-producing
if/switchused for concise variable initialization -
throws(SpecificError)used only where callers genuinely need exhaustive handling -
some Protocolchosen overany Protocolunless heterogeneous storage is required - Regex patterns use modern regex literals or
RegexBuilder - Property wrappers maintain thread safety and avoid re-entrant side effects
References
- Extended patterns and Codable examples: references/swift-patterns-extended.md
- Attributes and C interop: references/swift-attributes-interop.md