The subtleties of protocol extensions
One of those things that are not immediately obvious in Swift is that we can constrain an extension with a protocol in separate ways. Such as constraining an array with a protocol, or when using protocols as types. Let’s take a closer look.
Modeling data with a protocol
In the following code, we want to model the data-layer of a hot cryptocurrency startup application that wants to use the blockchain to apply machine learning and AI for internet of things (IoT) devices.
Using Swift on the backend, this app works with multiple types of cryptocurrencies which we’ll model in this article. We could consider putting all the types of currencies inside a single enum, but since this list can be enormous, a protocol is a better choice.
First, we model the protocol which we aptly name
CryptoCurrency. We use
NSDecimalNumber for handling currency. The
name represents the coin, and the
amount property represents how many—or a fraction—we have of a cryptocurrency.
We can, for example, have
BitCoin types that conform to the
Creating an extension
Some time passes, and we have our application up and running. We notice that we make use of repeated actions, such as figuring out the total price of the coins that we store inside arrays. For this, we can offer a convenient extension on
Array in which we offer a computed property called
totalPrice. This property is of type
NSDecimalNumber since we’re still dealing with currency.
When we have an array of coins, the
totalPrice property becomes instantly available. Below we’ll add a
BitCoin to an array, and we read out the
totalPrice, formatted by a
Note how we made the
coins array of type
[CryptoCurrency] since this array is heterogeneous.
totalPrice available as an extension makes much sense semantically, it saves us from coming up with a whole new structure or function to calculate our total price.
To implement the
totalPrice computed property, we start extending
Array. A first approach that we can take is to constrain
CryptoCurrency, by doing so we know that inside the extension,
Element is of type
CryptoCurreny; This allows us to use the properties of
Then, inside this extension, we’ll create a
totalValue computed property which loops through all coins while simultaneously building up the total price.
However, we’ll run into a shortcoming in our approach which we’ll fix shortly.
This extension is legit, however, it doesn’t work for heterogeneous arrays like ours. It works if all coins are of the same type. Let’s have a look.
First, we call
totalPrice on an array of
Bitcoin types which works just fine with our extension.
But, having the same coins repeated inside an array doesn’t work for our use-case, we have different coins that we want to mix in our array. If we try to mix currencies, we get an error when calling
The error that the compiler throws is
error: using ‘CryptoCurrency’ as a concrete type conforming to protocol ‘CryptoCurrency’ is not supported
What the compiler is telling us, is that when we have an array of
[CryptoCurrency] we’re using a protocol as a concrete type. However, in our extension, we used the protocols as a constraint. This is a mismatch that we’ll solve next.
Fixing our extension
To obtain the
totalPrice extension on a heterogeneous array, we have to create the extension a bit differently. We’ll use the
== instead of
: when defining our where clause.
: where clause, we offer an extension for elements that conform to
== where clause, we offer an extension for elements where the
CryptoCurrency is used as a type, e.g. an array of type
Below you can find the full extension that supports heterogeneous arrays.
Everything works, and now we can call
totalPrice on heterogeneous arrays.
It’s striking how one small symbol makes a world of difference. To better understand extensions, we have to understand using protocols as types versus using protocols as constraints. Not to mention that we have to keep an eye out for the symbol
Note that you can offer both extensions side-by-side to offer extensions for multiple scenarios.
Thanks for reading, I hope you enjoyed the article!
I'm Tjeerd (@tjeerdintveen), an iOS freelancer, avid Swift fan, and author.