';

Subscribe to The Swift Post

Enter your email address to subscribe to The Swift Post and receive notifications of new posts by email.

Generics in Swift 4


As one of the most powerful features in Swift, Generics can be tricky. A lot of people have trouble understanding and using them, especially application developers. Generics are most suitable for libraries, frameworks, and SDKs. In this post, I’ll try something different than other tutorials. We’ll open a restaurant and get a permission from SwiftyCity City Council. For the sake of integrity, I’ll try to keep things under four subjects.

  1. Generic Functions and Generic Types
  2. Protocols with Associated Types
  3. Generic Where Clauses
  4. Generic Subscripts

Here we go!

Generic Functions and Generic Types

Opening a Swift Restaurant

Let’s set up a new restaurant. While setting up, instead of focusing only our restaurant construction, we’ll also take a look at the legal part, the city council’s permission. Furthermore, we will focus on our own business to make it functional and profitable.
First, how does a company look like to The Council? A company should have some basic functionalities.

buy function adds the product to the inventory and it takes money out of company’s vault. On the other hand, sell function gets the product type, creates/finds the product and returns it in exchange for the money.

Generic Functions

In this protocol, Product being in actual type doesn’t sound right. Fitting every real product into Product type is not possible. Each product has different functionalities, properties and so on. Using an actual type in these kinds of functions is a really bad idea. Let’s turn back to The Council. All in the world, whatever each company does, it requires having to buy and sell capability. So, The Council has to find a generic solution for these two functions and make them work for every company. They can improve these functions using Generics:

So, we replaced our actual type Product with placeholder type T. The type parameter <T> defines these functions as generics. Placeholder types are replaced with actual types during compile time. So, the actual type will be determined whenever buy and sell functions used. This provides flexibility to use same functions for every product. For example, we’ll sell Penne Arrabiata in our Swift Restaurant. We can directly call sell function like following:

The compiler replaces T with PenneArrabiata‘s type during compilation time. When this method gets called in runtime, it will already have an actual type (PenneArrabiata) instead of a placeholder type. But there’s another problem. We can’t just buy and sell any type here, there needs to be something to define what we can legally buy and sell. This is where type constraints comes in. The Council has another protocol named LegallyTradable. It just checks and marks products that we can buy and sell legally. The Council forces us to apply this protocol to all trading operations. The Council will iterate over every product and adopt all suitable products to this protocol. So, we have to put type constraints to our generic functions to limit our functions’ usage for only allowed products.

Now, we can use these functions with inner peace. Basically, we put a constraint on our placeholder type T with saying “Only products which conform to LegallyTradable can be parameters of our Company protocol’s functions”. This constraint is called protocol as a constraint in Swift. If one product is not conforming to this protocol, it can’t be used as a parameter in this function.

Generic Types

Let’s move the focus to our restaurant. We got our permission and ready to focus on restaurant management. We hired a great manager and she wants to set up a system to keep track of every item in our inventory separately. In our restaurant, we have a wonderful pasta menu and our customers are going to love all kinds of pasta. That’s why we need a huge place to store pasta. We created a list of pasta packages and whenever chefs use a package, they remove it from the list. Also, whenever the restaurant buys a pasta package we’ll add it to our list. Lastly, our manager will order new packages if there are less than three packages in the list. Here is our PastaPackageList struct:

After a while, our manager started to think that we will need to create a list for each item in the restaurant to track them better. Instead of creating separate list structures every time, generics can help us in here. If we define our inventory list as a generic type, we can easily create new inventory lists with using the same struct implementation. Same as the generic functions, type parameter <T> defines our struct as generic. So we just need to replace PastaPackage actual type with placeholder type T.

This generic type gives us the ability to create separate inventory lists for each item in our inventory using the same implementation.

Another advantage of generic types is that whenever our manager needs some extra information like the first item in our inventory, we can write extensions to add the functionality. Swift allows us to write an extension for structs, classes, and protocols. While extending the generic type, we don’t need to provide type parameter as we do when defining structs. Yet, we can still use placeholder type in the extension. Let’s implement our manager’s request to understand better.

InventoryList‘s existing type parameter T is used to indicate the type of topItem without defining the type parameter again.
Now we have inventory lists for all products we have. We still don’t have a storage because every restaurant should apply to The Council for getting permission to store goods for long periods. So, let’s move our focus to The Council.

Protocols with Associated Types

We went to the city council again to get permission to store food. The Council stipulates some rules that we have to obey. For instance, every restaurant with storage should have their storage clean and put some certain foods away from each other. Also, The Council wants to check restaurants’ current inventory whenever they want. They provide a protocol which every store owner should conform. Again, this protocol cannot be specific to the restaurant. Because storage items can change for different types of shops and also for the restaurants. In Swift, generic protocols are implemented with associated types. Let’s have a look at the Storage protocol came from the city council.

Storage protocol doesn’t specify how the items in the storage should be stored or what type they are allowed to be. Any shop, restaurant that conforms to Storage protocol must be able to specify the type of values it stores. It has to ensure that correct type of items are added to and removed from storage. Also, it has to be able to show current inventory completely. So, for our storage, we can conform Storage protocol like following:

We conformed The Council’s Storage protocol. From now on, associated type Item is replaced with our Food type. Our restaurant’s storage is all available for Food. Associated type Item is just a placeholder type in protocols. We define the type with typealias keyword. But pointing out with this keyword is optional in Swift. Even if we don’t use typealias keyword it’ll still compile as long as we use our Food type in all places that Item uses in the protocol. Swift automatically handles this.

Constraining an Associated Type with Type Annotation

Like in real life, The Council always comes up with new rules and force you to obey them. After a while, The Council modifies their Storage protocol. They announce that they won’t allow every item in the Storage. Every Item must conform to StorableItem protocol to be sure they are suitable for storage. In other words, they constrained the associated type Item.

Using this method, The Council constrained the type for the current associated type. Anyone who conforms to Storage protocol now has to use type aliases which conform to StorableItem protocol.

Generic Where Clauses

Generic Types with a Generic Where Clause

Let’s go back to the beginning of the post and take a look at the Money type in our Company protocol. As we are all talking about protocols, money parameter of buy and sell functions was actually a protocol.

Again, after a while, The Council hit back to us with saying that they decided to have another rule. From now on, trading is only allowed with some currencies. Before that, we could use every kind of money in the type of Money. Instead of defining new money type for every currency, they decided to use Money protocol and changed the buy and sell functions as follows.

The difference between where clause and type constraint is where clauses are used to define requirements in associated type. In other words, we are not constraining the associated type inside the protocol. Instead, we’re constraining it while using the protocol.

Extension with a Generic Where Clause

Other usages of where clauses are in extensions. For instance, when The Council needs to print the money in a good format like “xxx EUR”, they can add an extension to Money with limiting its Currency to Euro

Generic where clause lets us add a new requirement to Money extension so that the extension adds the printAmount() method only when the Currency is Euro.

Associated Types with a Generic Where Clause

Our beloved council makes some improvements in Storage protocol. They want to iterate over each item and control them when they want to inspect if everything is OK. Controlling process is going to be different for each Item. Because of that, the council just provides iteration feature for Storage by adding an Iterator associated type.

Iterator protocol has associated type named Element and in here we add a requirement with saying the type of Element must be equal to the type of Item in the Storage protocol.

Generic Subscripts

It seems like requests from manager and council are endless. Also, we’re here to materialize their wishes. So, our manager came to us with saying that she wants to access storage items using a Sequence without accessing all items. Basically, the manager wants a syntax sugar.

In Swift 4, subscripts can be generic and we can use generic where clauses. In our usage, indices parameter has to conform Sequence protocol. From Apple doc, “The generic where clause requires that the iterator for the sequence must traverse over elements of type Int.” This ensures that the indices in the sequence are the same type as the indices used in storage.

Final Words

We made our restaurant fully functional. Our manager and The Council seems to be happy. As we can see from our journey, generics are really powerful. We can satisfy extensive requirements with ease using generics, once we get the concept. Generics are widely used in the Swift standard library. For instance, Array and Dictionary types are both generic collections. If you want to learn more and dive deep, you can always take a look at these classes and how they are implemented. Swift Language Doc also provides an extensive explanation for generics. Lastly, Swift language has Generic Manifesto which explains the features and future direction of generics. I suggest you take a look all documents to understand current usages and future plans.
Thanks for reading! Help spread the word.❤️ 🚀
Have questions, suggestions, comments or ideas for upcoming blog posts? Contact me on Twitter or write a comment! 😍 You can also follow me on GitHub.

Candost Dagdeviren

Software Developer. Technology and theater enthusiast. Starving for any kind of information.