Intro to Generics in Swift with Bob
I know you are frustrated. I’ve been there. Join me. I will walk you through.
Last update on May 15th, 2017 | Swift 3.1
Personal Story (You may skip)
As I was writing a blog post on Functional Programming in Swift, I realized readers must have a strong foundation in Generics
and Protocols
to survive through.
To find out if there were any good resources about generics, I clicked every link on the first 5 pages of the google search. After having gone through a couple, I’ve come to a conclusion that I had to do something about it — I felt the urgency to stand up for my readers. I could imagine their struggle and pain I went through.
Prerequisites
In order to fully enjoy this article with me, make sure you are familiar with protocols, OOP, functions, and extensions. If not, you may find all of the required resources available here which is my personal learning journey.
Since we are talking about generics, I’m going to use generic examples from the Swift 3 documentation. Of course, my explanation isn’t generic.
Your Past
Before we talk about anything else, let’s look into your past. How you were taught and brainwashed. Imagine you need to print each element within an array, you probably did this.
let stringArray = ["1", "2", "3", "4"]let intArray = [1, 2, 3, 4]let doubleArray = [1.1, 1.2, 1.3, 1.4]
Okay, let’s print.
func printStringFromArray(a: [String]) {
for s in a {
print(s)
}
}func printIntFromArray(a: [Int]) {
for i in a {
print(i)
}
}func printDoubleFromArray(a: [Double]) {
for d in a {
print(d)
}
}
The code above is just atrocious. It sucks. Each funtion only takes one specific type of an array. It repeats like an argument. We hate. Can there be just a single function that allows you to input any parameter whose type is undefined?
That was a rhetorical question. Of course. If there wasn’t, I’d have probably not written this article. Let’s deploy.
Generics, You Savage
Good. First of all, there is just one rule if you want to make your function generic. All you need to do is put <anything>
right next to a function name. Let’s take a look,
func savageGenerics<anything>(value: anything) {
print(value)
}savageGenerics(value: 123) // Int: Damn 😀
savageGenerics(value: "Bob") // String: Killing it 😲
savageGenerics(value: 123.12) // Double: Whoa 😵
savageGenerics(value: true) // Bool: I'm done 😱
Just bear with me for a sec. Just to clarify, when you input any type to value
, Swift automatically determines the type of value
based on the input. For example, if you call,
savageGenerics(value: “Bob”)
The value
type is now String
and it can be use within the function. If you call,
savageGenerics(value: false)
The value
type is now Bool
. I hope you are clear with me by now. Of course, you don’t have to call it as anything
. You can all it however you want.
func savageGenerics<T>(value: T) {
print(value)
}
Let’s Apply
Great, since we learned what generics is, let the show begin.
func printElement<T>(array: [T]) {
for element in array {
print(element)
}
}
So, all you have to is,
printElement(array: doubleArray) // 1.1 1.2 1.3 1.4
printElement(array: intArray) // 1 2 3 4
printElement(array: stringArray) // "1" "2" "3" "4"
One function takes it all. That’s why I call this a savage. If you are not familiar with this term, refer to Urban Dictionary.
So, let’s pull up Apple’s definition of Generics,
Generic code enables you to write flexible, reusable functions and types that can work with any type, subject to requirements that you define. You can write code that avoids duplication and expresses its intent in a clear, abstracted manner. — Swift Programming Language
In fact, Swift library that you use to interact with an array and dictionary has a lot of generic code.