Opaque result types are a useful tool for abstracting the return type of a function or subscript, or type of a property. Although the concrete underlying type of an opaque type is hidden from clients, it is still inferred by the compiler, which enforces certain usage requirements:
return
statement:let x: some Equatable // error: property declares an opaque return type, but has no initializer expression from which to infer an underlying type let y: some Equatable = 42 // OK let z: some Equatable { // Also OK return "hello, " + "world!" } func foo() -> some Equatable { // error: function declares an opaque return type, but has no return statements in its body from which to infer an underlying type fatalError("Unimplemented") } func bar() -> some Equatable { // OK fatalError("Unimplemented") return 42 }
return
statement in its body.func foo(bar: Bool) -> some Equatable { // error: function declares an opaque return type, but the return statements in its body do not have matching underlying types if bar { return "hello, world!" // note: return statement has underlying type 'String' } else { return 1 // note: return statement has underlying type 'Int' } } func bar(baz: Bool) -> some Equatable { // OK, both branches of the if statement return a value of the same underlying type, Int. if baz { return 100 } else { return 200 } }
return
statement that returns a concrete underlying type as opposed to the function's own opaque result type. Additionally, recursive calls may not be used to create an infinitely recursive opaque type.func foo(_ x: Int) -> some Equatable { // error: function declares an opaque return type, but has no return statements in its body from which to infer an underlying type // Not allowed because there aren't any non-recursive returns to infer the underlying type from. return foo(x+1) } struct EquatableWrapper<T: Equatable>: Equatable { var value: T } func foo() -> some Equatable { // error: function opaque return type was inferred as 'EquatableWrapper<some Equatable>', which defines the opaque type in terms of itself // Not allowed because the use of EquatableWrapper creates an infinitely recursive underlying type: EquatableWrapper<EquatableWrapper<EquatableWrapper<...>>>...> return EquatableWrapper(value: foo()) } func bar(_ x: Int) -> some Equatable { // OK, the underlying type can be inferred from the second return statement. if x > 0 { return bar(x-1) } else { return x } }
To learn more about opaque result types, see the Opaque Types section of The Swift Programming Language.