Swift Generics Tutorial: Getting Started

Learn to write functions and data types while making minimal assumptions. Swift generics allow for cleaner code with fewer bugs. By Michael Katz.

Leave a rating/review
Download materials
Save for later
Share
Update note: Michael Katz updated this tutorial for Swift 5. Mikael Konutgan wrote the original and Gemma Barlow updated for Swift 3.

Generic programming is a way to write functions and data types while making minimal assumptions about the type of data being used. Swift generics create code that does not get specific about underlying data types, allowing for elegant abstractions that produce cleaner code with fewer bugs. It allows you to write a function once and use it on different types.

You’ll find generics in use throughout Swift, which makes understanding them essential to a complete mastery of the language. An example of a generic you will have already encountered in Swift is the Optional type. You can have an optional of any data type you want, even those types you create yourself, of course. In other words, the Optional data type is generic over the type of value it might contain.

In this tutorial, you’ll experiment in a Swift playground to learn:

  • What exactly generics are.
  • Why they are useful.
  • How to write generic functions and data structures.
  • How to use type constraints.
  • How to extend generic types.

Getting Started

Begin by creating a new playground. In Xcode, go to File ▸ New ▸ Playground…. Select the macOS ▸ Blank template. Click Next and name the playground Generics. Finally, click Create!

As one of the few programmers residing in a kingdom far-far-away, you’ve been summoned to the royal castle to help the Queen with a matter of great importance. She has lost track of how many royal subjects she has and needs some assistance with her calculations.

She requests a function to be written that adds two integers. Add the following to your newly-created playground:

func addInts(x: Int, y: Int) -> Int {
  return x + y
}

addInts(x:y:) takes two Int values and returns their sum. You can give it a try by adding the following code to the playground:

let intSum = addInts(x: 1, y: 2)

This is a simple example that demonstrates Swift’s type safety. You can call this function with two integers, but not any other type.

The Queen is pleased, and immediately requests another add function be written to count her fortune —this time, adding Double values. Create a second function addDoubles(x:y:):

func addDoubles(x: Double, y: Double) -> Double {
  return x + y
}

let doubleSum = addDoubles(x: 1.0, y: 2.0)

The function signatures of addInts and addDoubles are different, but the function bodies are identical. Not only do you have two functions, but the code inside them is repeated. Generics can be used to reduce these two functions to one and remove the redundant code.

First, however, you’ll look at a few other common occurrences of generic programming in everyday Swift.

Other Examples of Swift Generics

You may not have realized, but some of the most common structures you use, such as arrays, dictionaries, optionals and results are generic types!

Arrays

Add the following to your playground:

let numbers = [1, 2, 3]

let firstNumber = numbers[0]

Here, you create a simple array of three numbers and then take the first number out of that array.

Now Option-click, first on numbers and then on firstNumber. What do you see?

Tooltip displayed when option-click is made on 'numbers'
Tooltip displayed when option-click is made on 'firstNumber'

Because Swift has type inference, you don’t have to explicitly define the types of your constants, but they both have an exact type. numbers is an [Int] — that is, an array of integers — and firstNumber is an Int.

The Swift Array type is a generic type. Generic types all have at least one type parameter, a placeholder for an as-yet unspecified other type. You need to specify this other type in order to specialize the generic type and actually create an instance of it.

For instance, the type parameter of Array determines what’s in the array. Your array is specialized so it can only contain Int values. This supports Swift’s type safety. When you remove anything from that array, Swift — and more importantly you — know it must be an Int.

You can better see the generic nature of Array by adding a slightly longer version of the same code to the playground:

var numbersAgain: Array<Int> = []
numbersAgain.append(1)
numbersAgain.append(2)
numbersAgain.append(3)

let firstNumberAgain = numbersAgain[0]

Check the types of numbersAgain and firstNumberAgain by Option-clicking on them; the types will be exactly the same as the previous values. Here you specify the type of numbersAgain using explicit generic syntax, by putting Int in angle brackets after Array. You’ve provided Int as the explicit type argument for the type parameter.

Try appending something else to the array, like a String:

numbersAgain.append("All hail Lord Farquaad")

You’ll get an error — something like: Cannot convert value of type ‘String’ to expected argument type ‘Int’. The compiler is telling you that you can’t add a string to an array of integers. As a method on the generic type Array, append is a so-called generic method. Because this array instance is of the specialized type Array<Int>, its append method is also now specialized to append(_ newElement:Int). It won’t let you add something of an incorrect type.

Delete the line causing the error. Next you’ll look at another example of generics in the standard library.

Dictionaries

Dictionaries are also generic types and result in type-safe data structures.

Create the following dictionary of magical kingdoms at the end of your playground, and then look up the country code for Freedonia:

let countryCodes = ["Arendelle": "AR", "Genovia": "GN", "Freedonia": "FD"]
let countryCode = countryCodes["Freedonia"]

Check the types of both declarations. You’ll see that countryCodes is a dictionary of String keys and String values — nothing else can ever be in this dictionary. The formal generic type is Dictionary.

Optionals

In the example above, note the type of countryCode is String?. This is in fact just a shorthand for Optional.

If the < and > look familiar, it’s because even Optional is a generic type. Generics are all over the place!

Here the compiler enforces that you can only access the dictionary with string keys and you always get string values returned. An optional type is used to represent countryCode, because there might not be a value corresponding to that key. If you try to look up “The Emerald City”, for example, the value of countryCode would be nil, as it doesn’t exist in your dictionary of magical kingdoms.

Note: For a more detailed introduction to Optionals, check out the Programming in Swift video on this site.

Add the following to your playground to see the full explicit syntax for creating an optional string:

let optionalName = Optional<String>.some("Princess Moana")
if let name = optionalName {}

Check the type of name, which you’ll see is String.

Optional binding, that is, the if-let construct, is a generic transformation of sorts. It takes a generic value of type T? and gives you a generic value of type T. That means you can use if let with any concrete type.

It’s T time!

iPhone wit a cup of tea