
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.
Leave a comment