Extensions
The square already works as a shape, and now it turns out you also need its perimeter. You could go back to the declaration of Square and add a property. But what if the type belongs to someone else, like Int from the standard library? You cannot edit its declaration.
Let's go back to the job openings and picture a training course. An employee attends it, learns a new skill and comes back the same person, only with a new ability. Nobody has to rewrite their personnel file for that.
In Swift an extension plays the part of such a course: it adds abilities to a type that is already declared, even one you did not write.
Extending an existing type
Let's teach whole numbers two new things:
extension Int {
var isEven: Bool { self % 2 == 0 }
func squared() -> Int { self * self }
}
let n = 7
print(n.isEven, n.squared()) // false 49
print(4.isEven) // trueLet's go through the program line by line:
extension Intopens an extension of the typeInt. Everything inside the braces goes to every whole number.var isEven: Boolis a computed property. Hereselfis the number itself, the one the property was asked of.func squared()is a new method: the number multiplies itself.n.isEvenandn.squared()are called as if they had been inIntfrom the start. Even the number4written right in the code now hasisEven.
Here the training-course picture is inaccurate. One employee attends a course, while an extension teaches the whole type at once. Every number in the program gets the new ability, including the ones created above the extension line.
Extending your own type
You extend your own types the same way. Code is often split like this: the type's declaration holds its data, and an extension holds what the type can do with it.
struct Square {
let side: Double
}
extension Square {
var perimeter: Double { side * 4 }
}
print(Square(side: 3).perimeter) // 12.0The properties from the declaration are visible inside an extension: perimeter computes from side, like an ordinary computed property.
Conformance in an extension
A badge can be earned at a course too. If a type was declared without a protocol, you add the conformance with an extension: write a colon and the protocol after the type's name, and meet its requirements inside.
protocol Shape {
func area() -> Double
}
extension Square: Shape {
func area() -> Double { side * side }
}
let shapes: [any Shape] = [Square(side: 3)]
print(shapes[0].area()) // 9.0Square was declared without : Shape, and now the square conforms to the protocol and goes into an [any Shape] array. In the same way someone else's type can conform to your protocol: extension Int: Shape with an area() method inside leaves the declaration of Int unchanged but gives it the badge.
What you can add
Interviewers like to ask this: what can you add with an extension, and what can't you? Of what you already know, an extension can add:
- computed properties;
- methods;
- type properties and type methods:
static letandstatic func; - an
initfor a struct, and the memberwise initializer does not disappear; - protocol conformance.
An ordinary stored property, which every instance has its own copy of, cannot be added with an extension. This is a common mistake with extensions, and we'll look at it separately.
Common mistake
An extension trying to give the square a color:
extension Square {
var color = "red" // ✗
}error: extensions must not contain stored propertiesThe program does not compile: an extension cannot add a stored instance property. Such properties make up the type's value itself, and the declaration sets their list. For example, an Int value takes 64 bits on computers and phones, and all the code that works with numbers relies on that. A static let type property, however, can be added by an extension: there is one for the whole type, and it is not part of any value.
An extension adds abilities, but it does not change what a value is made of: a course teaches a new skill, but it does not change the employee's height. The fix is to add var color = "red" to the declaration of Square, next to side.
Key points
- An extension adds abilities to a type that is already declared, even someone else's, like
Int, and every value of that type gets them. - An extension can add computed properties, methods, type properties and type methods, a struct's
initand protocol conformance. - An extension cannot add an ordinary stored property: such properties make up the value, and only the type's declaration sets them.