
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
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.