Protocol Oriented Programming — A beginner’s guide (Part One)

What the heck

I know, I know, how can a simple type like protocols be transformed into a new paradigm in programming? They are just contracts that object types (classes/ struct/ enums) conform to and all you gotta do is implement those methods, what is so special about this?! how will this help me!?

Don’t worry, I will answer all those questions in my part two. However, in this blog, I want to go over the basics first so we are all on the same page.

Here we go!

Protocols

In swift programming, protocols are everywhere and the uses for them can be sometimes confusing.

In order to understand how they operate and how to use correctly, I want to tell you a story about a clumsy chief.

So, once upon a time, there was a clumsy chief whom one day he decided to take on a random swift course online and make a smoothie/breakfast app, where the user let’s the app know what ingredients you have and outputs what smoothie and breakfast meal you can make based upon your input.

The app is simple, the chief would basically declare classes for the most common ingredients like so:

class Dairy {
func blend() {
print("Unknown dairy product blended")
}
}
class chesses: Dairy {
override func blend() {
print("DONT BLEND THIS")
}
}
class Milk: Dairy {
override func blend() {
print("Milk blended")
}
}
class fruit {

func blend() {
print("Unknown fruit has been blended")
}
}
class Avocado: fruit {
override func blend() {
print("Avocado blended")
}
}
class Apple: fruit {
override func blend() {
print("Apple blended")
}
}
class Lemon: fruit {
override func blend() {
print("DONT BLEND THIS FRUIT")
}
}
class Strawberry: fruit {
override func blend() {
print("Strawberries blended")
}
}

The logic behind the class definition are has follow:

The clumsy chief thought to himself: “I shall create two classes, one is Dairy and the other Fruit, I shall have a function inside that is called blend, so all the subclasses will inherit this blend function, with fruit or dairy products like cheese and lemon, I’ll just simple print out DO NOT BLEND and rely on the user’s common sense to not blend them​.

So far so good he thought. He later launched his app and received a One-Star rating on the app store, disappointed and defeated, he goes back to his drawing board and try to figure out how he can improve this code.

Then, one day he stumble upon a concept called Protocol, it is basically a contract you write up for a class to do a specific task listed in the protocol. In other words, you define (without implementation) the function of a protocol let the appropriate class conforms to it by implement the functions listed in the protocol. The chief thought to himself “why the heck would this be useful?!, I mean okay you define this thing called the protocol and define functions in it and later on you let classes conform to it, I guess this would make the code neatly right? why make things complicated and why would everyone find this useful?!

Well, protocols are extremely powerful once you realize that protocol is a full fledged type. What this means is that once a class is conformed to a protocol, that class becomes that type protocol. I know this is confusing so lets go back to the clumsy chief story.

​The chief soon realizes that protocol can be used as a type, he devised a plan to go around the problem. He rewritten his code as follow:

protocol Blendable {
func blend()
}
class Dairy {}
class chesses: Dairy {}
class Milk: Dairy {}
class fruit {}
class Avocado: fruit, Blendable {
func blend() {
print("Avocado has been blended")
}
}
class Apple: fruit, Blendable {
func blend() {
print("apple has been blended")
}
}
class Durian: fruit {
}
class Strawberry: fruit, Blendable {
func blend() {
print("Strawberries have been blended")
}
}
func blend(ingredients: [Blendable]) {

for ingredient in ingredients {
ingredient.blend()
}
}
let apple = Apple()
let avocado = Avocado()
let strawberry = Strawberry()
let fruitIngredients: [Blendable] = [apple, avocado, strawberry]
for fruits in fruitIngredients {
fruits.blend()
}
Outputs
// apple has been blended
// Avocado has been blended
// Strawberries have been blended

the chief declared a protocol called Blendable (keep in mind of the prefix -able). Now, he let classes that can be blended (like apples, avocado, banana etc) conform to the protocol blendable. Then, with classes that are conformed to the protocol he implement the methods. Effectively, what you are doing you are specifying classes that can do a certain thing (hence the prefix -able), the reason why inheriting the blend function is bad is because not all dairy or fruit products are suitable to blend (ie, cheese or durian), but since they inherit from Dairy and Fruit class, it will always have a default blend function, which we don’t have.

​Now here is the magic, the function blend has a argument of type Blendable, meaning that you only can pass in parameters that is conformed to this protocol. This way, we can define any class we want and if we think this dairy or fruit product is suitable to make a smoothie, we simply let the class conform to the Blendable protocol.

How protocol solved this problem is we specify a a function called blend and whoever can be blended will conform to this protocol. Notice the protocol name Blendable, you will notice sooner or later most swift standard protocols has the -able prefix meaning once you conform a class to this protocol, this class can now do a certain task listed by this protocol. For example, protocol Equatable and Comparable are protocol is swift, when your class conforms to them, that class can now be equatable and comparable. When would you use them? well say you can constructed two classes and you have a method that compares and equates them. Traditionally, we have taken these two protocol for granted because we use them all the time.

Protocols in action

​For example, print( 1==1) (equatable) and print(2 > 1) (comparable) and will return true, but how would you compare things print( cat == dog) or print (cat > dog)? you can’t, that is why your cat and dog class will need to conform to these protocols and define what is equatable and comparable mean in this class. Your next question might be “well, who exactly calls these functions specified in the protocol, sure in our smoothie app, I (me) was the one executed the function in the protocol in the func Blend(_:), when using the protocols in the swift standard library, who is calling these protocol functions? Well, that would be the compiler, in the inner workings of swift, there will be a function just like the blend function, where it take all the protocol types as a parameter and executing a task.

​For example, print( 1==1) (equatable) and print(2 > 1) (comparable) and will return true, but how would you compare things print( cat == dog) or print (cat > dog)? you can’t, that is why your cat and dog class will need to conform to these protocols and define what is equatable and comparable mean in this class. Your next question might be “well, who exactly calls these functions specified in the protocol, sure in our smoothie app, I (me) was the one executed the function in the protocol in the func Blend(_:), when using the protocols in the swift standard library, who is calling these protocol functions? Well, that would be the compiler, in the inner workings of swift, there will be a function just like the blend function, where it take all the protocol types as a parameter and executing a task.

Conclusion

There are a lot more I need to cover on this topic. In my part two of this series, I will discuss more on composition V.S. inheritance because it is where the strength on POP really is.

Leave a comment if you are confused and follow me to get notified of upcoming swift related blogs!

Thanks