| name | modern-swift-api-design |
| description | Use when designing or reviewing Swift protocols, generics, `some`/`any`, enums, domain types, associated types, typed throws, or public API resilience. Do not invoke for a local implementation change with no API decision. |
Modern Swift API design
Preserve relationships in the type system and introduce abstraction only for a demonstrated boundary.
Procedure
- State who chooses the concrete type: the implementation, the caller, or runtime data. This determines concrete types, opaque types/generics, or existentials.
- Model the domain states and invalid combinations. Prefer an enum or constrained value over correlated booleans and stringly typed cases.
- Decide the boundary's resilience, specialization, and heterogeneity requirements. Start concrete; use
some when one hidden type is returned, generics when a relationship must be preserved, and any when heterogeneous runtime values are required.
- Define protocol requirements around capabilities, not the current implementation. Do not create a protocol solely for mocking or to hide one private type.
- Keep errors untyped by default. Use typed throws only for a stable closed error contract, generic error preservation, or a proven constrained environment.
- Compile client-like examples, including inference, error handling, and the intended evolution point.
Guardrails
any P erases relationships; do not use it where two values must share an associated type or generic parameter.
some P hides one concrete type; it does not mean “any conformer” and is not a universal abstraction marker.
- A primary associated type improves constraints but does not remove the need to reason about identity and type relationships.
- Public API choices include source, ABI, and resilience consequences. Check library-evolution requirements before changing a shipped signature.
- Typed throws is additive precision, not a mandate to convert every
throws declaration.
Read references/type-choice-guide.md for the decision table and review traps. Use the compiler to validate inference rather than relying on remembered syntax.
Completion contract
Report the caller/implementation choice, the abstraction boundary, the invalid states excluded, the error contract, and client-facing proof.