Swift Opaque Types
An opaque return type names a protocol while hiding the concrete type behind it. The word some marks that one specific underlying type stands behind the result on every path.
Returning some Describable
The makeShape function returns a Circle, but its declaration names only the Describable protocol. The caller prints the result of the protocol method.
protocol Describable {
func describe() -> String
}
struct Circle: Describable {
var radius: Int
func describe() -> String {
return "Circle with radius \(radius)"
}
}
func makeShape() -> some Describable {
return Circle(radius: 3)
}
let shape = makeShape()
print(shape.describe())One underlying type can be compared
The fixedScore function returns the integer 42 behind some Equatable. Both calls share that underlying type, so the equality check prints true.
func fixedScore() -> some Equatable {
return 42
}
let first = fixedScore()
let second = fixedScore()
print(first)
print(first == second)Different underlying types fail
The pick function returns an integer on one branch and text on the other branch. The compiler rejects the function and reports the mismatch on the declaration line.
func pick(_ flag: Bool) -> some Equatable {
if flag {
return 1
} else {
return "one"
}
}
let value = pick(true)
print(value)Example
protocol Greeter {
func greet() -> String
}
struct FormalGreeter: Greeter {
func greet() -> String {
return "Good morning"
}
}
func makeGreeter() -> some Greeter {
return FormalGreeter()
}
let greeter = makeGreeter()
print(greeter.greet())Key points
- A function writes an opaque return type with some before a protocol name.
- The caller can use the requirements of that protocol.
- The caller cannot see the concrete type the function chose.
- Every return statement in the body must share the same underlying type.
- Branches that return different underlying types fail to compile.
- Two results from the same opaque function share one underlying type, so results can be compared when the protocol allows comparison.
In this example, the makeGreeter function hides the FormalGreeter type behind some Greeter. The caller stores the result without naming the concrete type. Calling the protocol method greet still runs the FormalGreeter version and prints its line.
Note
The concrete type stays fixed for a given function, even though callers never learn its name.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
A function declared to return some Equatable returns an integer on one branch and text on another branch. What happens?