Skip to content
Theory · Structs · lesson 6 of 9

Type properties and methods

Let's go back to the forms. Each filled-in form Size has its own numbers: one has width 2, another 5. But every form of this kind has the same header. It holds a filled-in sample, a 1 by 1 square, and a tip on how to quickly fill in a form for a square of any size.

The header belongs to the form itself, not to a single sheet. To read the sample, you don't need to fill in any form: it is the same for all of them.

Why would a program need this? Say a program often needs the size 1 by 1. You could declare it as a separate constant in the main part of the program. But then it lies far from Size, and you would have to search the whole program for it.

It is handier to keep such data inside the type, next to its properties. Swift has the word static for this:

SWIFT
struct Size {
    var width: Int
    var height: Int

    static let unit = Size(width: 1, height: 1)

    static func square(_ side: Int) -> Size {
        Size(width: side, height: side)
    }
}

let big = Size.square(5)
print(Size.unit.width, big.width) // 1 5

Let's walk through the program step by step:

  1. width and height are ordinary properties: each instance has its own.
  2. static let unit is the sample from the header: an instance of Size with width and height 1. It is stored in the type itself, not in the instances.
  3. static func square is the tip from the header: the method takes a side and returns a new instance, a square.
  4. Size.square(5) calls the method through the type's name. No instance is needed for that, and the result goes into big.
  5. print(Size.unit.width, big.width) prints 1 5.

Type properties

static let unit is a type property: it belongs to the type Size itself, not to an instance. Each instance has its own ordinary property, while there is one type property for the whole program.

A type property is read through the type's name: Size.unit. The expression Size.unit.width has two dots:

  • the first leads from the type to the type property: Size.unit is the sample instance;
  • the second leads from that instance to its ordinary property width.

You have already met a type property in the theme on operators: Int.max, the largest value of the type Int. It is also read through the type's name, and no number is needed for that.

Here the header picture is inaccurate. The header shows on every form, but an instance has no type property: it is stored in one place, in the type itself.

Only static let

In this course, type properties are declared with static let. A stored static var does not compile in Swift 6, even if the program never changes it. The line static var total = 0 inside a struct gives the error static property 'total' is not concurrency-safe because it is nonisolated global shared mutable state. The compiler itself suggests replacing var with let. The reason is the one that keeps a function from changing a var from the main part of the program: several parts of the program could change it at once.

Type methods

static func square is a type method. It is declared inside the type like an ordinary method, only with the word static, and called through the type's name: Size.square(5).

A type method is called without an instance, so it does not see the properties of any single instance. If you write width in its body, the compiler answers instance member 'width' cannot be used on type 'Size'. The method gets everything it needs through its parameters, as square gets side.

Often a type method builds a ready instance. The call Size.square(5) reads almost like a phrase: "a size that is a square with side 5".

Interviewers often ask about this: how does a type property or type method differ from an ordinary one? The answer has two parts:

  • each instance has its own ordinary property, while there is one type property for the whole program;
  • ordinary properties and methods are used through an instance, big.width, and type properties and methods through the type's name, Size.unit.

Common mistake

A type property is read through an instance:

SWIFT
print(big.unit.width) // ✗
TEXT
error: static member 'unit' cannot be used on instance of type 'Size'

The program does not compile. The instance big has only width and height, while unit is stored in the type Size itself. That is what the compiler says: a static property cannot be used on an instance of Size. Read it through the type's name: Size.unit.width.

Key points

  • There is one type property for the whole program, stored in the type itself; it is read through the type's name: Size.unit.
  • A type method is declared with static func and called through the type's name, with no instance: Size.square(5).
  • A type property cannot be read through an instance: big.unit does not compile.
  • A stored type property is declared with static let: static var does not compile in Swift 6.