ProgrammingiOS Developer, Middle/Senior

What are opaque types (some) in Swift, why are they needed, and when should they be used instead of protocol types?

Pass interviews with Hintsage AI assistant

Answer.

Background: Opaque types (some) were introduced in Swift 5.1 and provide a new way to abstract the return value of a function or property, where the type is known to the compiler but hidden from the user. This is an alternative to protocol existentials (any Protocol), but with a strict binding to a specific type within the function.

Problem: When a function returns a protocol with associatedtype (for example, Sequence), you cannot directly write:

func makeNumberSequence() -> Sequence { ... } // error

Protocol existentials allow returning any implementation but do not guarantee the same type on each call:

func foo() -> any View { ... }

This leads to unpredictability and weak type safety.

Solution: Use opaque result type:

func makeNumbers() -> some Sequence { [1, 2, 3] }

Now the compiler knows the actual return type for sure, but it is hidden externally. This provides performance optimizations, safety, allows for the use of SwiftUI DSL, and simplifies type exchange between modules.

Key features:

  • The specific type within the opaque type is always the same.
  • Does not support associatedtype at the usage site, only at the definition.
  • Used for building declarative APIs (e.g., SwiftUI).

Trick questions.

Can opaque types be used for storing a value (like class properties)?

No. Opaque types are only applicable for return values of functions or computed properties. For storing a value or an array of values, use existentials (any Protocol).

Can different branches of a single function return different types with some?

No. The compiler requires that both (or all) branches return the same specific type; otherwise, it will give an error:

func foo(flag: Bool) -> some Sequence { if flag { return [1, 2, 3] } else { return ["a", "b", "c"] // error } }

Can some be used to identify the return type between several functions?

No. Each function with some returns its unique hidden type, even if it is effectively the same array. You cannot use the result of one function as a parameter in another if both use some with different protocols or different hidden types.

Common mistakes and anti-patterns

  • Attempting to return different types through some (compilation error)
  • Using some where protocol existentials are required (e.g., for storing states)
  • Missing optimizations by continuing to use old-style protocol types

Real-life example

Negative case

In the project everything is returned through any Protocol, collections lose type safety, bugs appear during downcasting, and compile-time optimization slows down.

Pros:

  • Flexible architecture with the ability to combine different types.

Cons:

  • Loss of type safety, reduced efficiency, casting issues.

Positive case

In SwiftUI design, components return some View, each module clearly defines the internal type. Bundle size is reduced, build time is accelerated.

Pros:

  • Improved performance, increased type safety.

Cons:

  • Some loss of flexibility when dynamic storage is necessary.