Protocol Swift way of thinking

Protocol, Swift way of thinking



You ask any Swift lover, which features you love most on Swift. No doubt; it will be the way protocol works on Swift. Similar concepts like Interface lives on other languages, but the extensibility of protocol makes it shiny. By having protocol on its core Swift is build upon. So to understanding the Swift way of thinking protocol is a major milestone to cover. Apple emphasizes on Protocol-Oriented Programming over and over again on different WWDC events. Even further Apple suggested to have a mindset of think protocol first, before thinking about concrete implementation. But doesn’t it lead us to unnecessary abstraction? Well, we will talk all about those on this talk. It will be a nice long journey of protocol ride. So fasten your seatbelts.

Here on this blog post we will avoid the introductory talk of protocol like as; what is protocol, how protocol is defined and others. Because the Internet is full of those infos. Plus all the possible query about protocol from definition to extension, all are covered by the Swift Doc. But the practical use case of protocol is not covered there. And on that this blog post is dedicated.

The Swift Protocol Hub contains all the related posts with protocol. Be sure to check that out.

Background

This blog post is the third part of a six blog post series, where we are covering the composition over inheritance concept on Swift. The first blog post introduced us to how Inheritance initiates the code coupling. And the second blog post just broke down that code coupling through composition using protocol, which lays the foundation of this blog post. Finally we will build a case study on the current blog post to cover the above topics start to end. So let us dive deep.

What facilities protocol provides

protocol acts like a contract between two types. One type confirms to implements the protocol‘s required func and var as per contract and the other type utilizes those func and var as the program required.

The very first thing protocol provides us, is the ability to maximizing the usage of value type rather than the reference type on our code base. Building Better Apps with Value Types in Swift on WWDC 2015 – Session 414 got a nice details touch on value type and why value type is more suitable than the reference type.

After that, protocol facilitates composition. In order to facilitate the composition the two types need to have a has a relationship among them. So whenever we can define a has a relationship we can immediately implement the delegation patterns, and obviously delegation patterns are provided through protocol on Swift. Let us make it more transparent through an example.

By implementing the protocol-oriented programming on our code base, our code base becomes more decoupled and flexible for future changes.

A case study of Avengers

This time we will build our case study on Avengers, super hero team of Marvel. On the way of building the case study we will feature the protocol oriented solution.

On the very initial stage we will start with IronMan and CaptainAmerica to initiate the team. But later on Hulk, Thor will join the Avengers.

It is confirm that all the Avenger will have a name. Do you asking me, How do I know? Oh come on! A nameless super hero on town, who gonna believe that? 🤓

Some code then.

protocol Avenger{
    var name: String {get}
}

struct IronMan: Avenger{
    var name = "Iron Man"
}

struct CaptainAmerica: Avenger{
    var name = "Captain America"
}

struct Hulk: Avenger{
    var name = "Hulk"
}

struct Thor: Avenger{
    var name = "Thor"
}

let initialTeam: [Avenger] = [IronMan(), CaptainAmerica(), Hulk(), Thor()]
initialTeam.forEach({ print($0.name) })

Ok it is a very basic implementation, do not think we need any more details explanation other than why we are using protocol and struct?

Well if we don’t use protocol then we need to use class instead of struct. Because only class can have inheritance through a base class. But class has its own overhand. class are expensive than value type. Plus here we do not have any specific reason to choose class. On Apple’s developer blog choosing between struct and class been discussed, we can always visit to refreshed our memory.

Btw forEach is a Higher order function, HOF. Here on mobidevtalk we have some good talk on HOF, You can visit those to gain a solid understanding on HOF for Swift.

Identifying has a relationship

As we can already imagine, there will be a lot of versatility on our Avengers. It will be really tough to define some common ground among them. As one among them is a regular human, one is a super human, another one is a God and the other one is a transformable mutant who on normal state is a humble human. OMG 😲! A lot of dissimilarity to handle.

But on a contrary all of them has some common properties among them. Like wise they all are special, not normal dudes. Didn’t mean abnormal though 😉. So they can have a common property called speciality, and that speciality property have to be defined by the corresponding Avenger.

Can we guess the relationship among the speciality and the individual Avenger? Isn’t a single Avengers has a speciality? Aha, that’s it. It is a has a relationship. So here we can set a composition through protocol among the Avengers and speciality.

By adding speciality property on Avenger we get the following code:

protocol Avenger{
    var name: String {get}
    var speciality: String {get}
}

struct IronMan: Avenger{
    var name = "Iron Man"
    var speciality = "Iron Man got the coolest gadgets. Techie and smart 😎"
}

struct CaptainAmerica: Avenger{
    var name = "Captain America"
    var speciality = "Super Human power. Quick to heal, tough to beat. 💪"
}

struct Hulk: Avenger{
    var name = "Hulk"
    var speciality = "God like power. Good at smashing 🔥"
}

struct Thor: Avenger{
    var name = "Thor"
    var speciality = "God of Thunder ⚡️"
}

let initialTeam: [Avenger] = [IronMan(), CaptainAmerica(), Hulk(), Thor()]
initialTeam.forEach({print($0.name + ": " + $0.speciality)})

As we can see, we find out a has a relationship among the code and immediately we can implement the protocol to achieve the composition.

Facilitating as needed

Protocol is the best way to provide the as needed concept on Swift. Let us consider the avengers who possess some defensive mechanism.

protocol Defense: Avenger{
    var defenseSystem: String { get }
}

extension IronMan: Defense{
    var defenseSystem: String{
        get{
            return "The suite itself contains the defensive counter measure"
        }
    }
}

extension CaptainAmerica: Defense{
    var defenseSystem: String{
        get{
            return "The shield is the main defense"
        }
    }
}

extension Thor: Defense{
    var defenseSystem: String{
        get{
            return "The spinning Hammer is the defense"
        }
    }
}

let defenseHolder = initialTeam.compactMap { (avenger) -> Defense? in
    if let defense = avenger as? Defense{
        return defense
    }
    return nil
}
defenseHolder.forEach({ print($0.name + "'s Defense system is: " + $0.defenseSystem) })

As we can see the Hulk does not have any special defensive mechanism, so Hulk did not confirm to Defense protocol. Other avengers did adopt the Defense protocol as they possess the required property. As needed is achieved through protocol.

If we have not yet seen we are adopting the Avenger protocol on Defense protocol, to constraint the Defense protocol. So every Defense is Avenger. As a result we can print the defenseSystem with the corresponding Avenger’s name.

Protocol-oriented programming terminology and explanation

When we use OOP, we thing Object as the core and design the whole solution of a problem by splitting the total problem into smaller subproblem and assign those subproblem into different Objects. Then those Objects hold the properties to represent the subproblem domain. Now the Object has the data and the function to resolve the subproblem. By interacting with different Object we solve the core problem.

On protocol-oriented programming, we break down the whole big problem into smaller subproblem and assign those subproblems to different protocol. Now the protocol will hold the signature of those subproblem. By adopting the protocol we will solve each of the subproblem one by one and finally the original problem.

On our previous two talks, we shifts our mind set to Composition from Inheritance only by introducing a very simple problem of cape for the superhero 😉. Those two blog post are crucial to have a better grabs on Protocol-oriented programming.

Now let us consider the current blog post where we use the Protocol-oriented programming at first place.

Our problem was to team up the Avengers. The Avengers has some similarities and some dissimilarities.

We pick the common properties and put them on a single protocol, Avengers. Then we put the dissimilarities like defenseSystem into another protocol Defense.

So we break our whole problem into smaller subproblem and represent them by protocol. Then the other type like, IronMan, CaptainAmerica, Hulk, Thor adopt those protocol and implement it on their own way. By resolving the smaller problem we solve the whole problem. Protocol-oriented programming is achieved now 🥳.

Resources

End Talk

As always all the corresponding code is pushed on GitHub, feel free to have a look.

The talk about protocol can not be completed within a single talk. We have to define the scope of this talk for keeping the length of this blog as short as possible 🧐.

Intensionally we are pushing some talks for the next protocol talk. Talks like unnecessary abstraction, facilitating test even dependency inversion needed to be discussed on a separated talk. So stay tunes, we will be back with another protocol talk on Swift. Till then take care.

4 thoughts on “Protocol, Swift way of thinking

Leave a Reply

Notifications for mobidevtalk! Cool ;) :( not cool