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.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Swift Generics Tutorial: Getting Started
25 mins
- Getting Started
- Other Examples of Swift Generics
- Arrays
- Dictionaries
- Optionals
- Results
- Writing a Generic Data Structure
- Writing a Generic Function
- Constraining a Generic Type
- Cleaning Up the Add Functions
- Extending a Generic Type
- Subclassing a Generic Type
- Enumerations With Associated Values
- Where to Go From Here?
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?
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.
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.