Install
Terminal · npx$
npx skills add https://github.com/vercel-labs/agent-skills --skill vercel-react-native-skillsWorks with Paperclip
How Swift Language fits into a Paperclip company.
Swift Language drops into any Paperclip agent that handles this kind of work. Assign it to a specialist inside a pre-configured PaperclipOrg company and the skill becomes available on every heartbeat — no prompt engineering, no tool wiring.
S
SaaS FactoryPaired
Pre-configured AI company — 18 agents, 18 skills, one-time purchase.
$27$59
Explore packSource file
SKILL.md495 linesExpandCollapse
---name: swift-languagedescription: "Apply modern Swift language patterns and idioms for non-concurrency, non-SwiftUI code. Covers if/switch expressions (Swift 5.9+), typed throws (Swift 6+), result builders, property wrappers, opaque and existential types (some vs any), guard patterns, Never type, Regex builders (Swift 5.7+), Codable best practices (CodingKeys, custom decoding, nested containers), modern collection APIs (count(where:), contains(where:), replacing()), FormatStyle (.formatted() on dates, numbers, measurements), and string interpolation patterns. Use when writing core Swift code involving generics, protocols, enums, closures, or modern language features."--- # Swift Language Patterns Core Swift language features and modern syntax patterns targeting Swift 6.3. Covers language constructs, type system features, Codable,string and collection APIs, formatting, C interop (`@c`), module disambiguation (`ModuleName::symbol`), and performance attributes (`@specialized`, `@inline(always)`). For concurrency (actors, async/await,Sendable), see the `swift-concurrency` skill. For SwiftUI views and statemanagement, see `swiftui-patterns`. ## Contents - [If/Switch Expressions](#ifswitch-expressions)- [Typed Throws](#typed-throws)- [Result Builders](#result-builders)- [Property Wrappers](#property-wrappers)- [Opaque and Existential Types](#opaque-and-existential-types)- [Guard Patterns](#guard-patterns)- [Never Type](#never-type)- [Regex Builders](#regex-builders)- [Codable Best Practices](#codable-best-practices)- [Modern Collection APIs](#modern-collection-apis)- [FormatStyle](#formatstyle)- [String Interpolation](#string-interpolation)- [Common Mistakes](#common-mistakes)- [Review Checklist](#review-checklist)- [References](#references) ## If/Switch Expressions Swift 5.9+ allows `if` and `switch` as expressions that return values. Use themto assign, return, or initialize directly. ```swift// Assign from if expressionlet icon = if isComplete { "checkmark.circle.fill" } else { "circle" } // Assign from switch expressionlet label = switch status {case .draft: "Draft"case .published: "Published"case .archived: "Archived"} // Works in return positionfunc color(for priority: Priority) -> Color { switch priority { case .high: .red case .medium: .orange case .low: .green }}``` **Rules:**- Every branch must produce a value of the same type.- Multi-statement branches are not allowed -- each branch is a single expression.- Wrap in parentheses when used as a function argument to avoid ambiguity. ## Typed Throws Swift 6+ allows specifying the error type a function throws. ```swiftenum ValidationError: Error { case tooShort, invalidCharacters, alreadyTaken} func validate(username: String) throws(ValidationError) -> String { guard username.count >= 3 else { throw .tooShort } guard username.allSatisfy(\.isLetterOrDigit) else { throw .invalidCharacters } return username.lowercased()} // Caller gets typed error -- no cast neededdo { let name = try validate(username: input)} catch { // error is ValidationError, not any Error switch error { case .tooShort: print("Too short") case .invalidCharacters: print("Invalid characters") case .alreadyTaken: print("Taken") }}``` **Rules:**- Use `throws(SomeError)` only when callers benefit from exhaustive error handling. For mixed error sources, use untyped `throws`.- `throws(Never)` marks a function that syntactically throws but never actually does -- useful in generic contexts.- Typed throws propagate: a function calling `throws(A)` and `throws(B)` must itself throw a type that covers both (or use untyped `throws`). ## Result Builders `@resultBuilder` enables DSL-style syntax. SwiftUI's `@ViewBuilder` is the mostcommon example, but you can create custom builders for any domain. ```swift@resultBuilderstruct ArrayBuilder<Element> { static func buildBlock(_ components: [Element]...) -> [Element] { components.flatMap { $0 } } static func buildExpression(_ expression: Element) -> [Element] { [expression] } static func buildOptional(_ component: [Element]?) -> [Element] { component ?? [] } static func buildEither(first component: [Element]) -> [Element] { component } static func buildEither(second component: [Element]) -> [Element] { component } static func buildArray(_ components: [[Element]]) -> [Element] { components.flatMap { $0 } }} func makeItems(@ArrayBuilder<String> content: () -> [String]) -> [String] { content() } let items = makeItems { "Always included" if showExtra { "Conditional" } for name in names { name.uppercased() }}``` **Builder methods:** `buildBlock` (combine statements), `buildExpression` (single value), `buildOptional` (`if` without `else`), `buildEither` (`if/else`), `buildArray` (`for..in`), `buildFinalResult` (optional post-processing). ## Property Wrappers Custom `@propertyWrapper` types encapsulate storage and access patterns. ```swift@propertyWrapperstruct Clamped<Value: Comparable> { private var value: Value let range: ClosedRange<Value> var wrappedValue: Value { get { value } set { value = min(max(newValue, range.lowerBound), range.upperBound) } } var projectedValue: ClosedRange<Value> { range } init(wrappedValue: Value, _ range: ClosedRange<Value>) { self.range = range self.value = min(max(wrappedValue, range.lowerBound), range.upperBound) }} // Usagestruct Volume { @Clamped(0...100) var level: Int = 50} var v = Volume()v.level = 150 // clamped to 100print(v.$level) // projected value: 0...100``` **Design rules:**- `wrappedValue` is the primary getter/setter.- `projectedValue` (accessed via `$property`) provides metadata or bindings.- Property wrappers can be composed: `@A @B var x` applies outer wrapper first.- Do not use property wrappers when a simple computed property suffices. ## Opaque and Existential Types ### `some Protocol` (Opaque Type) The caller does not know the concrete type, but the compiler does. Theunderlying type is fixed for a given scope. ```swiftfunc makeCollection() -> some Collection<Int> { [1, 2, 3] // Always returns Array<Int> -- compiler knows the concrete type}``` Use `some` for:- Return types when you want to hide implementation but preserve type identity.- Parameter types (Swift 5.9+): `func process(_ items: some Collection<Int>)` -- equivalent to a generic `<C: Collection<Int>>`. ### `any Protocol` (Existential Type) An existential box that can hold any conforming type at runtime. Has overheadfrom dynamic dispatch and heap allocation. ```swiftfunc process(items: [any StringProtocol]) { for item in items { print(item.uppercased()) }}``` ### When to choose | Use `some` | Use `any` ||---|---|| Return type hiding concrete type | Heterogeneous collections || Function parameters (replaces simple generics) | Dynamic type erasure needed || Better performance (static dispatch) | Protocol has `Self` or associated type requirements you need to erase | **Rule of thumb:** Default to `some`. Use `any` only when you need aheterogeneous collection or runtime type flexibility. ## Guard Patterns `guard` enforces preconditions and enables early exit. It keeps the happy pathleft-aligned and reduces nesting. ```swiftfunc processOrder(_ order: Order?) throws -> Receipt { // Unwrap optionals guard let order else { throw OrderError.missing } // Validate conditions guard order.items.isEmpty == false else { throw OrderError.empty } guard order.total > 0 else { throw OrderError.invalidTotal } // Boolean checks guard order.isPaid else { throw OrderError.unpaid } // Pattern matching guard case .confirmed(let date) = order.status else { throw OrderError.notConfirmed } return Receipt(order: order, confirmedAt: date)}``` **Best practices:**- Use `guard` for preconditions, `if` for branching logic.- Combine related guards: `guard let a, let b else { return }`.- The `else` block must exit scope: `return`, `throw`, `continue`, `break`, or `fatalError()`.- Use shorthand unwrap: `guard let value else { ... }` (Swift 5.7+). ## Never Type `Never` indicates a function that never returns. It conforms to all protocolssince Swift 5.5+ (bottom type). ```swift// Function that terminates the programfunc crashWithDiagnostics(_ message: String) -> Never { let diagnostics = gatherDiagnostics() logger.critical("\(message): \(diagnostics)") fatalError(message)} // Useful in generic contextsenum Result<Success, Failure: Error> { case success(Success) case failure(Failure)}// Result<String, Never> -- a result that can never fail// Result<Never, Error> -- a result that can never succeed // Exhaustive switch: no default needed since Never has no casesfunc handle(_ result: Result<String, Never>) { switch result { case .success(let value): print(value) // No .failure case needed -- compiler knows it's impossible }}``` ## Regex Builders Swift 5.7+ Regex builder DSL provides compile-time checked, readable patterns. ```swiftimport RegexBuilder // Parse "2024-03-15" into componentslet dateRegex = Regex { Capture { /\d{4}/ }; "-"; Capture { /\d{2}/ }; "-"; Capture { /\d{2}/ }} if let match = "2024-03-15".firstMatch(of: dateRegex) { let (_, year, month, day) = match.output} // TryCapture with transformlet priceRegex = Regex { "$" TryCapture { OneOrMore(.digit); "."; Repeat(.digit, count: 2) } transform: { Decimal(string: String($0)) }}``` **When to use builder vs. literal:**- Builder: complex patterns, reusable components, strong typing on captures.- Literal (`/pattern/`): simple patterns, familiarity with regex syntax.- Both can be mixed: embed `/.../` literals inside builder blocks. ## Codable Best Practices ### Custom CodingKeys Rename keys without writing a custom decoder: ```swiftstruct User: Codable { let id: Int let displayName: String let avatarURL: URL enum CodingKeys: String, CodingKey { case id case displayName = "display_name" case avatarURL = "avatar_url" }}``` ### Custom Decoding Handle mismatched types, defaults, and transformations: ```swiftstruct Item: Decodable { let name: String let quantity: Int let isActive: Bool init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) name = try container.decode(String.self, forKey: .name) quantity = try container.decodeIfPresent(Int.self, forKey: .quantity) ?? 0 if let boolValue = try? container.decode(Bool.self, forKey: .isActive) { isActive = boolValue } else { isActive = (try container.decode(String.self, forKey: .isActive)).lowercased() == "true" } } enum CodingKeys: String, CodingKey { case name, quantity; case isActive = "is_active" }}``` ### Nested Containers Flatten nested JSON into a flat Swift struct: ```swift// JSON: { "id": 1, "metadata": { "created_at": "...", "tags": [...] } }struct Record: Decodable { let id: Int let createdAt: String let tags: [String] enum CodingKeys: String, CodingKey { case id, metadata } enum MetadataKeys: String, CodingKey { case createdAt = "created_at" case tags } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) id = try container.decode(Int.self, forKey: .id) let metadata = try container.nestedContainer( keyedBy: MetadataKeys.self, forKey: .metadata) createdAt = try metadata.decode(String.self, forKey: .createdAt) tags = try metadata.decode([String].self, forKey: .tags) }}``` See [references/swift-patterns-extended.md](references/swift-patterns-extended.md) for additional Codable patterns(enums with associated values, date strategies, unkeyed containers). ## Modern Collection APIs Prefer these modern APIs over manual loops: ```swiftlet numbers = [1, 2, 3, 4, 5, 6, 7, 8] // count(where:) -- Swift 5.0+, use instead of .filter { }.countlet evenCount = numbers.count(where: { $0.isMultiple(of: 2) }) // contains(where:) -- short-circuits on first matchlet hasNegative = numbers.contains(where: { $0 < 0 }) // first(where:) / last(where:)let firstEven = numbers.first(where: { $0.isMultiple(of: 2) }) // String replacing() -- Swift 5.7+, returns new stringlet cleaned = rawText.replacing(/\s+/, with: " ")let snakeCase = name.replacing("_", with: " ") // compactMap -- unwrap optionals from a transformlet ids = strings.compactMap { Int($0) } // flatMap -- flatten nested collectionslet allTags = articles.flatMap(\.tags) // Dictionary(grouping:by:)let byCategory = Dictionary(grouping: items, by: \.category) // reduce(into:) -- efficient accumulationlet freq = words.reduce(into: [:]) { counts, word in counts[word, default: 0] += 1}``` ## FormatStyle Use `.formatted()` instead of `DateFormatter`/`NumberFormatter`. It istype-safe, localized, and concise. ```swift// Dateslet now = Date.nownow.formatted() // "3/15/2024, 2:30 PM"now.formatted(date: .abbreviated, time: .shortened) // "Mar 15, 2024, 2:30 PM"now.formatted(.dateTime.year().month().day()) // "Mar 15, 2024"now.formatted(.relative(presentation: .named)) // "yesterday" // Numberslet price = 42.5price.formatted(.currency(code: "USD")) // "$42.50"price.formatted(.percent) // "4,250%"(1_000_000).formatted(.number.notation(.compactName)) // "1M" // Measurementslet distance = Measurement(value: 5, unit: UnitLength.kilometers)distance.formatted(.measurement(width: .abbreviated)) // "5 km" // Duration (Swift 5.7+)let duration = Duration.seconds(3661)duration.formatted(.time(pattern: .hourMinuteSecond)) // "1:01:01" // Byte countsInt64(1_500_000).formatted(.byteCount(style: .file)) // "1.5 MB" // Lists["Alice", "Bob", "Carol"].formatted(.list(type: .and)) // "Alice, Bob, and Carol"``` **Parsing:** `FormatStyle` also supports parsing:```swiftlet value = try Decimal("$42.50", format: .currency(code: "USD"))let date = try Date("Mar 15, 2024", strategy: .dateTime.month().day().year())``` ## String Interpolation Extend `DefaultStringInterpolation` for domain-specific formatting. Use `"""` for multi-line strings (indentation is relative to the closing `"""`). See [references/swift-patterns-extended.md](references/swift-patterns-extended.md) for custom interpolation examples. ## Common Mistakes 1. **Using `any` when `some` works.** Default to `some` for return types and parameters. `any` has runtime overhead and loses type information.2. **Manual loops instead of collection APIs.** Use `count(where:)`, `contains(where:)`, `compactMap`, `flatMap` instead of manual iteration.3. **`DateFormatter` instead of FormatStyle.** `.formatted()` is simpler, type-safe, and handles localization automatically.4. **Force-unwrapping Codable decodes.** Use `decodeIfPresent` with defaults for optional or missing keys.5. **Nested if-let chains.** Use `guard let` for preconditions to keep the happy path at the top level.6. **String regex for simple operations.** Use `.replacing()` and `.contains()` before reaching for Regex.7. **Ignoring typed throws.** When a function has a single, clear error type, typed throws give callers exhaustive switch without casting.8. **Overusing property wrappers.** A computed property is simpler when there is no reuse or projected value needed.9. **Building collections with `var` + `append` in a loop.** Prefer `map`, `filter`, `compactMap`, or `reduce(into:)`.10. **Not using if/switch expressions.** When assigning from a condition, use an expression instead of declaring `var` and mutating it. ## Review Checklist - [ ] `some` used over `any` where possible- [ ] `guard` for preconditions; collection APIs instead of manual loops- [ ] `.formatted()` used instead of `DateFormatter`/`NumberFormatter`- [ ] Codable types use `CodingKeys` for API mapping; `decodeIfPresent` with defaults for optional fields- [ ] if/switch expressions for conditional assignment; property wrappers have clear reuse justification- [ ] Regex builder used for complex patterns (literal OK for simple ones)- [ ] String interpolation is clean; no unnecessary `String(describing:)`- [ ] Typed throws used when callers benefit from exhaustive error handling- [ ] `Never` used appropriately in generic contexts ## References - Extended patterns and Codable examples: [references/swift-patterns-extended.md](references/swift-patterns-extended.md)- Attributes and C interop (`@c`, `@specialized`, `@inline(always)`, `@export`, `ModuleName::symbol`): [references/swift-attributes-interop.md](references/swift-attributes-interop.md)