Swift 5.1 introduces Opaque return types as a new language feature. It can be used to return a value’s type for functions and properties without demonstrating the concrete type of the value. The return type will be of some type that implements the protocol.
Wrap-type information can be used at boundaries between any module and source code. Because the type of the return value can remain secret. Unlike returning a value whose type is a protocol type, opaque types preserve type identity—the compiler has access to the type information, but clients of the module don’t.
It always refers to one specific, concrete type – which is hidden from us while in the case of the protocol type can refer to many types, as they conform to the protocol.
Implementation of Opaque Types
To more clarification about the opaque return type and why it is different than just using the protocol as a return type. Let’s discuss with examples how we can use it.
Declaring Protocol with associatedtype:
Associated types are a powerful way of making protocols generic or opaque, but they can be a bit confusing at first.
Let’s add a protocol called Vehicle. This protocol has an associatedtype called Type. Vehicle protocol that can store any type those items depend on whatever conforms to the protocol, but we can still use them inside the protocol and any extensions.
1 2 3 4 |
protocol Vehicle { associatedtype Types func call(type: Types)-> Types } |
Concrete types of the Protocol:
Now add three concrete types for this protocol as OnRoad, OnSKy and OnWater. All are different types as
1 2 3 4 5 6 7 8 9 10 11 12 13 |
struct OnRoad : Vehicle{ func call(type: Car) -> Car { return type } } struct Car { var car: String init(car: String) { self.car = car } } |
Here, OnRoad conforms to the protocol with parameter as Car type and that returns the type as Car.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
struct OnWater: Vehicle { func call(type: Boat) -> Boat { return type } } struct Boat { var boatName: String var boatModel: Float init(boatName: String,boatModel: Float ) { self.boatName = boatName self.boatModel = boatModel } } |
OnWater conforms to the protocol with parameter as Boat type and that returns the type as Boat.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
struct OnSky: Vehicle{ func call(type: Aeroplane) -> Aeroplane { return type } } struct Aeroplane { var aeroplaneName: String var aeroplaneModel: Int init(aeroplaneName: String, aeroplaneModel: Int ) { self.aeroplaneName = aeroplaneName self.aeroplaneModel = aeroplaneModel } } |
And OnSky conforms to the protocol with parameter as well as returns the type as Boat.
Handle Cases of Vehicle Protocol:
Now for handling the case of Vehicle protocol values defined in an enumeration as:
1 2 3 4 5 |
enum Way{ case onRoad case onSky case onWater } |
Returning an Opaque Type:
Now we’re going to define a function like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
func selectRoadWay() -> some Vehicle { // Doesn't know type of `Vehicle` here. return OnRoad(types: Car(car: "Car")) // Here it does get the type `Vehicle`. } func selectSkyWay() -> some Vehicle { // Doesn't know type of `Vehicle` here. return OnSky(types: Aeroplane(aeroplaneName: "Jet Air Lines", aeroplaneModel: 789643)) // Here it does get the type `Vehicle`. } func selectWaterWay() -> some Vehicle { // Doesn't know type of `Vehicle` here. return OnWater(types: Boat(boatName: "Deck Boats", boatModel: 678.20)) // Here it does get the type `Vehicle`. } |
The returns a value of type Vehicle and uses some keyword to denote that this is an opaque type. It’s up to the function to get what concrete type is returned. Above written function returning the different values in the bodies.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
func selectWay(way: Way) { switch way { case .onSky: let skyWay = selectSkyWay() print(skyWay) case .onRoad: let roadWay = selectRoadWay() print(roadWay) case .onWater: let waterWay = selectWaterWay() print(waterWay) } } let byWater = selectWay(way: .onWater) //Output: OnWater(types: Opaque_Type.Boat(boatName: "Deck Boats", boatModel: 678.2)) let byRoad = selectWay(way: .onRoad) //Output: OnRoad(types: Opaque_Type.Car(car: "Car")) let bySky = selectWay(way: .onSky) //Output: OnSky(types: Opaque_Type.Aeroplane(aeroplaneName: "Jet Air Lines", aeroplaneModel: 789643)) //Build successfully |
Printed out the result of its return type of functions.
Conclusion
I hope this blog will help you in the understanding of Opaque type if you have any comments, questions, or recommendations, feel free to post them in the comment section below!
For other blogs, please click here.