# Applying Protocol-Oriented Programming in Development

Oct 17 2023 · Swift 5.9, iOS 17, Xcode 15

## Lesson 01: Introduction to Protocol-Oriented Programming

### Episode complete

Play next episode

Next
Transcript

## Demo

To really compare the differences between protocols and inheritance, it’s time to write some code! In this demo, you’ll implement the code for `FamilyCar` and see how to use the types in a simple app. You’ll then build the same functionality into a type using inheritance to compare the two different approaches.

First, open the starter playground from this lesson’s materials. Inside `FamilyCar`, implement `move()`:

``````// 1
let travelingSpeed: Double
if speed < 0 {
travelingSpeed = 0
} else if speed > maxSpeed {
travelingSpeed = maxSpeed
} else {
travelingSpeed = speed
}
// 2
let distance = travelingSpeed * duration
// 3
if direction == .backwards {
totalDistanceTraveled = totalDistanceTraveled - distance
print("Traveled -\(distance)")
} else {
totalDistanceTraveled = totalDistanceTraveled + distance
print("Traveled \(distance)")
}
``````

This does the following:

1. Works out the speed the car is traveling, ensuring it’s not less than 0 or greater than the maximum speed.
2. Calculates the distance traveled by multiplying the speed by the duration.
3. Adds the distance traveled to the total distance traveled — or subtracts it, if the car is traveling backwards.

Now that you’ve implemented `move()`’s functionality, you can see how to use the function. First, create an instance of `FamilyCar` to call the function on.

``````let familyCar = FamilyCar()
``````

Then, call `move()` on the `FamilyCar` a couple of times and print the details to run through the implementation and see how to call the functions on your type:

``````familyCar.move(direction: .forward, duration: 15, speed: 30)
familyCar.move(direction: .forward, duration: 15, speed: 60)
print(familyCar.showDetails())
``````

Run the playground; you’ll see the message appear in the console.

Next, implement `move()` in `VehicleType`. You can copy and paste the code from `FamilyCar`:

``````let travelingSpeed: Double
if speed < 0 {
travelingSpeed = 0
} else if speed > maxSpeed {
travelingSpeed = maxSpeed
} else {
travelingSpeed = speed
}
// 2
let distance = travelingSpeed * duration
// 3
if direction == .backwards {
totalDistanceTraveled = totalDistanceTraveled - distance
print("Traveled -\(distance)")
} else {
totalDistanceTraveled = totalDistanceTraveled + distance
print("Traveled \(distance)")
}
``````

You’ve now implemented the function for the inheritance option. Note that you’re implementing the code in the superclass; therefore, you don’t need to implement it in the subclass.

Next, create an instance of `FamilyCarInheritance` and call the same functions as the protocol implementation to see how to use it:

``````let familyCar2 = FamilyCarInheritance()
familyCar2.move(direction: .forward, duration: 15, speed: 30)
familyCar2.move(direction: .forward, duration: 15, speed: 60)
print(familyCar2.showDetails())
``````

This has the same output as the protocol implementation. Up to this point, there’s no real difference.

One of the advantages of using protocols in Swift is you can leverage the compiler to check your code for you. At the bottom of the playground, create a new vehicle that conforms to the protocol:

``````class Truck: Vehicle {

}
``````

See how you already get an error from the compiler because the type is missing the properties and functions that the protocol requires. Use Xcode’s Fix-It shortcut to add the stubs for you.

Next, implement `showDetails()`:

``````"I am a truck"
``````

Then, implement `move(direction:duration:speed:)`. Again, you can copy and paste the code from `FamilyCar`:

``````let travelingSpeed: Double
if speed < 0 {
travelingSpeed = 0
} else if speed > maxSpeed {
travelingSpeed = maxSpeed
} else {
travelingSpeed = speed
}
let distance = travelingSpeed * duration
if direction == .backwards {
totalDistanceTraveled = totalDistanceTraveled - distance
print("Traveled -\(distance)")
} else {
totalDistanceTraveled = totalDistanceTraveled + distance
print("Traveled \(distance)")
}
``````

Finally, create an initializer:

``````init() {
self.numberOfWheels = 6
self.maxSpeed = 30
self.totalDistanceTraveled = 0
}
``````

The protocol defines `numberOfWheels` and `maxSpeed` as immutable, but you can still mutate them inside your type… which might make sense for your implementation. From the API perspective, it’s read-only.

To demonstrate this, create a `Truck` and set the number of wheels to 12:

``````let truck = Truck()
truck.numberOfWheels = 12
``````

There’s nothing wrong with this code, and it compiles just fine. If you set the type of `truck` to be `Vehicle`, it will fail to compile because the API does not match what the protocol defines:

``````let truck: Vehicle = Truck()
truck.numberOfWheels = 12
``````

Remove the `type` annotation so your playground compiles again.

``````let truck = Truck()
truck.numberOfWheels = 12
``````

Finally, change `totalDistanceTraveled` to a `let` in `Truck`:

``````let totalDistanceTraveled: Double
``````

This time, you do get an error because the protocol defines the API of `Vehicle` to have a mutable property called `totalDistanceTraveled`. This doesn’t exist in your new `Truck` implementation. Change your code back so it compiles.