Skip to content

Instantly share code, notes, and snippets.

@LeeKahSeng
Last active August 2, 2022 15:00
Show Gist options
  • Save LeeKahSeng/a347da1778c71f55537eda991bd56c64 to your computer and use it in GitHub Desktop.
Save LeeKahSeng/a347da1778c71f55537eda991bd56c64 to your computer and use it in GitHub Desktop.
Full sample code for article "How to Achieve Dynamic Dispatch Using Generic Protocols in Swift 5.7" (https://swiftsenpai.com/uncategorized/dynamic-dispatch-with-generic-protocols)
protocol Vehicle {
associatedtype FuelType: Fuel
var name: String { get }
func startEngin()
func fillGasTank(with fuel: FuelType)
}
struct Car: Vehicle {
let name: String
func startEngin() {
print("\(name) enjin started!")
}
func fillGasTank(with fuel: Gasoline) {
print("Fill \(name) with \(fuel.name).")
}
}
struct Bus: Vehicle {
let name: String
func startEngin() {
print("\(name) enjin started!")
}
func fillGasTank(with fuel: Diesel) {
print("Fill \(name) with \(fuel.name).")
}
}
protocol Fuel {
associatedtype FuelType where FuelType == Self
static func purchase() -> FuelType
}
struct Gasoline: Fuel {
let name = "gasoline"
static func purchase() -> Gasoline {
print("Purchase gasoline from gas station.")
return Gasoline()
}
}
struct Diesel: Fuel {
let name = "diesel"
static func purchase() -> Diesel {
print("Purchase diesel from gas station.")
return Diesel()
}
}
// MARK: - Functions
func startAllEngin(for vehicles: [any Vehicle]) {
for vehicle in vehicles {
vehicle.startEngin()
}
}
func fillAllGasTank(for vehicles: [any Vehicle]) {
for vehicle in vehicles {
fillGasTank(for: vehicle)
}
}
func fillGasTank(for vehicle: some Vehicle) {
let fuel = type(of: vehicle).FuelType.purchase()
vehicle.fillGasTank(with: fuel)
}
// MARK: - Execution
let vehicles: [any Vehicle] = [
Car(name: "Car_1"),
Car(name: "Car_2"),
Bus(name: "Bus_1"),
Car(name: "Car_3"),
]
startAllEngin(for: vehicles)
fillAllGasTank(for: vehicles)
@LeeKahSeng
Copy link
Author

As of now (Swift 5.7), there is only 1 way to convert opaque type to existential type and vice versa, which is by using a function parameter. Thus using as will not work. Furthermore, in order for the conversion to work, the function parameter must be of type any or some, using [any] or [some] will not work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment