🎓 A1Learner
🔍
0 of 27 lessons completed

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?