Adding to an existing structure with extensions
Sometimes you want to add functionality to a structure but don't want to muddy up the original definition. Sometimes you can't add the functionality because you don't have access to the source code. It is possible to open an existing structure (even one you do not have the source code for) and add methods, initializers and computed properties to it. This can be useful for code organization and is discussed in greater detail in Chapter 19. Doing so is as easy as using the keyword, extension.
At the bottom of your playground, outside the definition of Math, add this type method called primeFactors(of:):
extension Math {
static func primeFactors(of value: Int) -> [Int] {
// 1
var remainingValue = value
// 2
var testFactor = 2
var primes: [Int] = []
// 3
while testFactor * testFactor <= remainingValue { if remainingValue % testFactor == 0 {
primes.append(testFactor) remainingValue /= testFactor
}
else {
testFactor += 1
}
}
if remainingValue > 1 { primes.append(remainingValue)
}
return primes
}
}
This method finds the prime factors for a given number. For example, 81 returns
[3, 3, 3, 3]. Here's what's happening in the code:
- The value passed in as a parameter is assigned to the mutable variable,
remainingValue so that it can be changed as the calculation runs.
- The testFactor starts as two and will be divided into remainingValue.
- The logic runs a loop until the remainingValue is exhausted. If it evenly divides, meaning there's no remainder, that value of the testFactor is set aside as a prime factor. If it doesn't evenly divide, testFactor is incremented for the next loop.
This algorithm is brute force, but does contain one optimization: the square of the testFactor should never be larger than the remainingValue. If it is, the remainingValue itself must be prime and it is added to the primes list.
You've now added a method to Math without changing its original definition. Pretty slick, eh! You're about to see how that's powerful in practice.
Note: It is not possible to add stored properties to an existing structure because that would change the size and memory layout of the structure and break existing code.