Generic Functions
Part of the Object Oriented Programming section of Coddy's Swift journey. Lesson 34 of 57.
A generic function works with any type. The placeholder in angle brackets, often T, stands for the type the caller uses, and Swift fills it in at each call:
func firstAndLast<T>(_ items: [T]) -> [T] {
guard let first = items.first, let last = items.last else { return [] }
return [first, last]
}
print(firstAndLast([3, 8, 1]))
print(firstAndLast(["a", "b", "c"]))Output:
[3, 1]
["a", "c"]Inside the function nothing is known about T, so only operations that work for every type are allowed. A constraint such as T: Comparable allows more, here the < operator:
func largest<T: Comparable>(_ items: [T]) -> T? {
guard var best = items.first else { return nil }
for item in items where item > best { best = item }
return best
}
print(largest([4, 9, 2])!)
print(largest(["pear", "apple", "zucchini"])!)Output:
9
zucchiniGenerics keep the exact type, unlike Any. The result of largest on [Int] is an Int?, so it can be used in arithmetic without casting:
func largest<T: Comparable>(_ items: [T]) -> T? {
items.max()
}
let top = largest([3, 7, 5]) ?? 0
print(top * 10)Output:
70A function can have several placeholders, and constraints can name protocols of your own:
protocol Scored { var score: Int { get } }
struct Player: Scored { let name: String; let score: Int }
struct Team: Scored { let score: Int }
func total<T: Scored>(_ items: [T]) -> Int {
items.reduce(0) { $0 + $1.score }
}
func pair<A, B>(_ a: A, _ b: B) -> String { "\(a) & \(b)" }
print(total([Player(name: "a", score: 3), Player(name: "b", score: 4)]))
print(total([Team(score: 10)]))
print(pair(1, "one"))Output:
7
10
1 & oneChallenge
EasyWrite the generic function countWhere(_:_:) that takes an array of any type and a predicate (T) -> Bool and returns how many elements pass, and mostCommon(_:) that takes an array of any Hashable type and returns its most frequent element (the one that appears first in the array when counts tie), or nil for an empty array.
The supplied code reads a comma-separated line of words and a line of numbers. It prints the number of words longer than 3 characters, the most common word, the number of even numbers and the most common number.
Your code goes in Functions.swift. main.swift holds the supplied input/output code and cannot be edited.
Try it yourself
// Supplied input/output code: keep it as it is
var input: [String] = []
while let line = readLine() { input.append(line) }
let words = input[0].split(separator: ",").map(String.init)
let numbers = input[1].split(separator: ",").map { Int($0)! }
print(countWhere(words) { $0.count > 3 })
print(mostCommon(words) ?? "none")
print(countWhere(numbers) { $0 % 2 == 0 })
print(mostCommon(numbers).map { String($0) } ?? "none")
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Classes and Objects
Working With FilesDefining ClassesMethods and selfInitializersClasses Are ReferencesRecap - Library Card4Encapsulation
Access ControlRead-Only From OutsideGuarding StateFailable InitializersRecap - Bank Account7Polymorphism and Generics
PolymorphismType CastingGeneric FunctionsGeneric TypesRecap - Shape Calculator5Inheritance
SubclassesOverriding MethodsInitializers and superfinal and HierarchiesRecap - Employee Hierarchy11Project: Library Management
Books and MembersBorrowing BooksPractice on your own: Swift playground