Discover that Swift does not allow multiple inheritance for classes, yet with protocol composition, Swift types can adopt multiple protocols.
- [Instructor] Protocol composition is one of the pillars of the protocol-oriented programming paradigms. Swift doesn't allow multiple inheritance for classes. But with protocol composition, Swift types can adopt multiple protocols. Why is this so important? By conforming to multiple protocols, we can ensure our types only implement the requirements they really need. Instead of inheriting unnecessary noise from a class hierarchy, our types will only adopt the protocols they need for their proper functionality.
Let's demonstrate how protocol composition works. So far, we've been using types that adopted either one or another protocol. With protocol composition, we can create types that conform to multiple protocols. For example, what if we need a struct, let's call it simply MyData, that provides support for persistence and base64 encoding. All we need to do is make it adopt both the BinaryPersistable and Base64Encodable protocol.
So let's adopt the Base64Encodable and the BinaryPersistable protocol. Now this code won't compile, so we have to add the missing properties. Actually, all we need is to add the tag and the data properties. Add data of type data. Since we have default implementation available through protocol extensions, the structure is very brief. If we need a custom description, we can make our struct conform to the CustomStringConvertible protocol.
So let's add it here. The CustomStringConvertible protocol defines a description property requirement. Let's implement it. Var description, it's a string, and I'm going to simply return the name of the struct and its stack property, which is MyData, and the tag property. Now what if we need to check whether two MyData instances are equal? All we need to do is to adopt the Equatable protocol.
The static equal to operator let's us compare whether two MyData values are equal. So let's implement it. It's a static method which takes a left-hand side argument of type MyData and a right-hand side argument, which is also of type MyData. It returns a Boolean value. It's up to us how to implement the equal to operator, but in this case, it's enough to compare both the tag and the data values included in the given instances.
So let's simply return the result of this evaluation. We compare the tags of both sides, and add the data. We can add as many protocols to the type inheritance list as we need. Alternatively, we can use type extensions for each feature protocol conformance. So let's quickly de-factor our struct. I'm going to create a dedicated extension for the custom description.
Extension MyData, which is CustomStringConvertible, and I simply copy and paste the description method here. Now we can remove the description methods from the structure, and also the protocol conformance. I do the same for the Equatable part. Let's create another extension, also for MyData.
Equatable, and I'm going to move the equal to operator to this extension. Now our original structure became less cluttered and way shorter than before. The result is the same, but our code will be better organized and easier to follow. Protocol composition allows for a granular design. Our types must only adopt the protocols they need for their proper functionality.
- Comparing object-oriented programming with protocol-oriented programming
- Methods and class-bound protocols
- Adopting a protocol
- Declaring asynchronous behavior
- Preparing and implementing fallback logic
- Implementing an app using protocol-oriented programming