The Best Feature of Swift: Protocols

Efrain Gonzalez
4 min readOct 4, 2021

--

Protocols make up the heart of Swift’s language design

When I was in college, I would get into debates with friends about programing languages over lunch. We would go on and on about Java or Python and OOP this, syntax that (and by we I mostly mean me). To be honest though, despite the fun I had, I realize that most imperative programing languages are similar enough to where debating them isn’t really worth the effort.

Sure you could debate over Java’s boilerplate or Python’s multithreading issues, but most languages have very similar features (OOP, lambda functions, etc) wrapped around some variation of a C syntax. At the end of the day, a language doesn’t make a huge radical difference as to how you think about the structure of your code.

Recently, I’ve been looking more into the Swift Language at the recommendation of a colleague. At first, Swift seemed similar to most other languages I ran into (especially Javascript). Then I ran into protocols.

I would argue that protocols are Swift’s most interesting departure from normal imperative language features. If you are interested in learning a new language but not sure which one to try, I think that protocols may convince you to give Swift a shot.

At first they may seem similar enough to C++ interfaces or Java abstract classes. Interfaces, Abstracts, and protocols all both allow implementation of a declared structure in a class that inherits them. Where they differ though, is less in their actual capabilities in but in their context.

How I learned to stop worrying and love extensions

Swift comes with a feature called extensions. As the name implies, you can use these to extend classes and protocols beyond their original implementations. The most important part of this is how they make protocols the most powerful part of Swift.

With extensions, you can not only add more implementation details to protocols, but you can also extend class implementations that already exist to implement (called conforming in Swift) a protocol.

Imagine, for example, that you had a class implemented in a library that acts as a container you want to iterate though using a for-in loop. This class has no currently has no implementation that allows for iteration. In a language like C++, you would probably think to either edit the source code of the library or wrap it in your own class that has iteration built in. In Swift, the solution is far more elegant: you simply write an extension that extends the class to conform to the Sequence protocol.

The extension allows the programmer to write the implementation needed for the class in question to conform to the sequence protocol, as well as declaring to the language that the class does in fact conform the protocol. Once done, the class gets all the features guaranteed in the protocol. Protocols can also be somewhat used as a type in Swift, meaning that anything that can accept Sequences as an input can also accept your class.

Extending a Protocol

From what I’ve said so far, you may be inclined to believe that it’s actually extensions that are the best part of Swift. Where protocols come in is in what they add to Swift by being extended. A protocol can be extended to include implementations, not just declarations. This means that you can use a protocol not just to require certain attributes in a class, but also provide functionality in the case that those requirements are met.

In the Swift standard library, the Sequence protocol actually contains many of the standard functions that you would expect from array in javascript, such as Map and Reduce. This means that if you conform to the Sequence protocol, your class gets access to these functions. This is novel as far as OOP goes, but becomes powerful by extending a protocol that you never wrote yourself. Suddenly it becomes possible to add features to multiple standard library or third-party library types with only one extension to a protocol.

Let’s go back to our example library from earlier. If you wanted to add functions to array to support your third-party library, it would be trivially easy to do just by adding extensions to sequence. The best part is that on top of supporting array, you would be adding the feature to every class that conforms sequence.

A more concrete example

So far I’ve been giving vague examples, so let’s look at something more realistic. In Swift, there’s a function called reversed() for arrays that returns the reversed form of the array it is called on. It doesn’t, however, return a normal array type. It in fact returns a structure called ReversedCollection, which wraps around the Array type in order to return the reversed collection lazily. Normally, this would be invisible to the user since ReversedCollection inherits all the functions that Array has since they both conform to similar protocols. This means, however, that if you were to write a function to extend array with an extension, ReversedCollection would not support it. This also brakes the ‘invisibility’ built into ReversedCollection, since the user would notice when they try to run your function on ReversedCollection.

The solution is to find a protocol that both types conform to and extend that protocol. This would make it so that they both have the function when called which maintains the invisibility inherit to the ReversedCollection type. In another language, the solution may have involved writing a generic function that supports both ReversedCollections and Arrays. In that situation, however, the function would not be a part of the classes but outside of it. It would be a far less elegant solution that simply adding the function to the objects themselves.

I wrote this post after feeling inspired when reviewing some of the official Swift documentation. If you’re interested in Swift after reading this, I would recommend reading through the Language Guide.

Thanks for reading. This is my first post on medium so comments are appreciated. Check out my website at efrain.io.

--

--