Protocols

The evolution of structs into class-like things that can hold properties and methods in Swift raised in my mind “what about inheritance?” – but no: structs in Swift can not use inheritance.

Swift classes implement inheritance, but only from one class; there’s no multiple inheritance. Protocols neatly address both these concerns to a large extent, but perhaps before we look at how they work, we should have a brief diversion into inheritance in C++.

#include <iostream>

class Shape {
    public:
    int sides;
};


class Drawable {
    public:
        virtual void draw() {}
};


class Square : public Shape, public Drawable {
    public:
        Square(){
            sides = 4;
        }
        
        void draw() {
            std::cout << "■" << std::endl;
        }
};

int main() {
    Square square;
    square.draw();
    return 0;
}

In the code above, there’s two classes Shape and Drawable. You could regard Drawable as an interface if you’re coming from Java world (because the method draw() is marked virtual – there’s no implementation). The class Square inherits from both those classes – it’s a new class that is a Shape, but is also Drawable. (Line 15 above)

Perhaps in this program there’s other items such as images or text – ie not shapes which might also inherit from Drawable. Elsewhere, we could have a method that had to draw a collection of things – it doesn’t care what the items are, as long as they are Drawable – they have to implement the Draw() method.

Swift addresses most of these needs with Protocols. A protocol defines a set of properties and methods. Then a struct, class, or even enum can conform with this protocol – they contain the same properties, and are required by the compiler to implement the methods from the protocol.

Here’s the Swift equivalent of the C++ above:

protocol Shape {
    var sides: Int { get set }
}

protocol Drawable {
    func draw()
}

struct Square:  Shape, Drawable {
    var sides: Int = 4
    func draw() {
        print("■")
    }
}

let square = Square()
square.draw()

So, that’s cool, but not amazing. The power is really that now we can write a function that takes anything that’s Drawable as if it was a real type. To wit:

class IanClass: Drawable {
    func draw() {
        print("Ian")
    }
}

func drawAThing(_ thingToDraw: Drawable){
    thingToDraw.draw()
}

let squareStruct = Square()
let ianClass = IanClass()

drawAThing(squareStruct)
drawAThing(ianClass)

So the function drawAThing() is happy to draw anything, as long as it conforms with the Drawable protocol by implementing the draw() method. It doesn’t even matter what it is – as in this example where we’ve passed it a struct on one occasion, and a class on another.

Protocols are a great example of Swift being flexible while being type-safe.

One response to “Protocols”

  1. Playgrounds are good – dev.endevour Avatar

    […] couple of times (Protocols & Named Loops) in the past few days I’ve needed to write and run a couple of tiny C or […]

    Like

Leave a comment