Understanding Opaque Return Types in Swift

Diving into the example of using Opaque return types.

Declaring Protocol with associatedtype

protocol MobileOS {
associatedtype Version
var version: Version { get }
init(version: Version)
}

Implementing concrete types of the Protocol

struct iOS: MobileOS {
var version: Float
}
struct Android: MobileOS {
var version: String
}

Create Function to return the Protocol type

Solution 1 (Returns Protocol Type):

func buildPreferredOS() -> MobileOS {
return iOS(version: 13.1)
}
// Compiler ERROR 😭
Protocol 'MobileOS' can only be used as a generic constraint because it has Self or associated type requirements

Solution 2 (Returns Concrete Type):

func buildPreferredOS() -> iOS {
return iOS(version: 13.1)
}
// Build successfully

Solution 3 (Generic Function Return)

func buildPreferredOS<T: MobileOS>(version: T.Version) -> T {
return T(version: version)
}
let android: Android = buildPreferredOS(version: "Jelly Bean")
let ios: iOS = buildPreferredOS(version: 5.0)

Final Solution (Opaque Return Type to the rescue 😋:)

func buildPreferredOS() -> some MobileOS {
return iOS(version: 13.1)
}

Opaque returns types can only return one specific type

func buildPreferredOS() -> some MobileOS {
let isEven = Int.random(in: 0...100) % 2 == 0
return isEven ? iOS(version: 13.1) : Android(version: "Pie")
}
// Compiler ERROR 😭
Cannot convert return expression of type 'iOS' to return type 'some MobileOS'
func buildPreferredOS() -> some MobileOS {
let isEven = Int.random(in: 0...100) % 2 == 0
return isEven ? iOS(version: 13.1) : iOS(version: "13.0")
}
// Build Successfully 😎

Simplify complex and nested type into an opaque return type for the API Caller

func sliceFirstAndEndSquareProtocol<T: Numeric>(array: Array<T>) -> LazyMapSequence<ArraySlice<T>, T> {
return array.dropFirst().dropLast().lazy.map { $0 * $0 }
}
sliceFirstAndEndSquareProtocol(array: [2,3,4,5]).forEach { print($0) }
// 9
// 16
func sliceHeadTailSquareOpaque<T: Numeric>(array: Array<T>) -> some Sequence {
return array.dropFirst().dropLast().lazy.map { $0 * $0 }
}
sliceHeadTailSquareOpaque(array: [3,6,9]).forEach { print($0) }
// 36

Opaque Return Types in SwiftUI

struct Row: View {
var body: some View {
HStack {
Text("Hello SwiftUI")
Image(systemName: "star.fill")
}
}
}
HStack<TupleView<(Text, Image)>>

Learning more about Opaque return type

Conclusion

Mobile Developer and Lifelong Learner. Currently building super app @ Go-Jek. Xcoding with Alfian at https://alfianlosari.com

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store