04
Product
16
Backend
09
Auth
12
iOS
07
Infra
02
Real-Time

Use Result types for specific scenarios

ADR-0011 ACCEPTED · 2025-07-13
Use Result types for specific scenarios, prefer async throws generally

Context

The LLM introduced Result types into the iOS authentication service. While Result types force explicit success/failure handling, async throws is the idiomatic Swift pattern for service APIs — simpler call sites, build-time safety (forgotten error handling causes build errors), and alignment with Swift 6's typed throws direction.

Result types have their place, but not as the default for service APIs.

Decision

Default to async throws for iOS service APIs. Reserve Result types and typed throws for specific scenarios.

When to use Result types

Use Result<T, Error> for:

  1. Cross-Boundary Operations

    • Passing results across threads or async boundaries
    • Storing success/failure state in memory or persistence
    • Integration with completion handler-based APIs
  2. Functional Composition

    • Complex operation chaining with map/flatMap
    • Promise-like patterns across different types/errors
  3. Explicit State Management

    • When the result itself needs to be a first-class value
    • APIs where callers need to inspect or transform errors before handling

When to use async throws

  • Direct service operations (authentication, network calls, data fetching)
  • Simple utility functions
  • Most business logic where errors are propagated and rendered rather than handled exhaustively

When to use typed throws (Swift 6+)

  • Module-internal code with stable error types
  • Generic code that only propagates user-provided errors
  • When you need compile-time guarantees about specific error types

Consequences

Simpler, more idiomatic Swift. Call sites use try/catch instead of switching on Result. Forgotten error handling causes build errors with throws, which is a safety net Result doesn't give you.

The trade-off is that throws allows errors to be silently propagated without explicit handling, and generic Error types lose domain-specific information (mitigated by typed throws in Swift 6).

References