---
title: Enumerations
source: 'https://academia.sh/en/courses/swift/enumerations'
course: 'The Swift Language'
language: en
updated: '2026-10-21T05:03:12+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Measures the rawValue and init(rawValue:) paths of an enumeration with raw values'
    - 'Shows that an associated value is evaluated once, when the case is constructed'
    - 'Reads from the output that pattern matching with switch binds the associated value to a name'
    - 'Measures that a computed property in an enumeration runs again on every read'
---

# Enumerations

Measuring when a raw value and an associated value are set up, how pattern matching opens them, and why a computed property runs on every read.

The previous lesson measured types that are lists of fields: structures and classes always carry the same fields. Some data, however, calls not for a list of fields but for being in one of several distinct states. A day of the week is one of seven values; a measurement is either a number in degrees or a label. These two examples describe different things, but both are expressed with an **enumeration**.

A Swift enumeration is more powerful than its counterpart in many languages. Each `case` is not only a name; depending on its definition it can have a **raw value**, or an **associated value** that travels with the case. Enumerations can also carry computed properties and methods; they cannot carry stored instance properties. The lesson first measures when these two kinds of value are set up, and then when a computation inside an enumeration runs. The course's measuring axis does not change: **when is this expression evaluated?** There are four moments: immediately, on first use, on every use, never. The `Probe` class is given below exactly as it is.

## The Core

Every lesson uses the same core. `Probe` counts how many times an expression is evaluated (`eval`) and how many times it is used (`use`); the `moment` property derives the moment from those two numbers. In the binding measurement of the opening lesson, the distribution over eight expressions was 2/1/3/2: two immediately, one on first use, three on every use, two never. In this lesson we measure only our own slice.

```swift
// Probe.swift — records when an expression is evaluated
final class Probe {
    let label: String
    private(set) var evaluations = 0
    private(set) var uses = 0
    private var evaluatedBeforeUse = false

    init(_ label: String) {
        self.label = label
    }

    func eval<T>(_ value: T) -> T {
        evaluations += 1
        if uses == 0 { evaluatedBeforeUse = true }
        return value
    }

    func use<T>(_ access: () -> T) -> T {
        uses += 1
        return access()
    }

    var moment: String {
        if evaluations == 0 { return "never" }
        if evaluations > 1 { return "on-every-use" }
        return evaluatedBeforeUse ? "immediately" : "on-first-use"
    }

    func report() {
        print("\(label): \(evaluations) evaluations, \(uses) uses -> \(moment)")
    }
}

func tally(_ probes: [Probe]) {
    for moment in ["immediately", "on-first-use", "on-every-use", "never"] {
        let count = probes.filter { $0.moment == moment }.count
        print("\(moment): \(count)")
    }
}
```

The measurements use two enumerations. `Weekday` has an `Int` raw value and lists all its cases through `CaseIterable`; when the first case is given `1`, the following ones become `2` and `3`. `Reading` carries a value with its cases: `celsius` takes a `Double`, `label` takes a `String`. This block has no output, because it only defines the types.

```swift
// Types.swift — enumerations with raw values and with associated values
enum Weekday: Int, CaseIterable {
    case monday = 1, tuesday, wednesday
}

enum Reading {
    case celsius(Double)
    case label(String)
}
```

## Raw Values

A raw value is the counterpart assigned to a case as a constant at compile time. The raw value of each case must be different, and the values are written in the definition. When `1` is written for the first case, the values of the following cases are determined by adding one each time. The raw value is reached through the `rawValue` property, and to go the other way, from a raw value to a case, the form `Weekday(rawValue: 3)` is used. It is clear that the reverse direction cannot find a case for every raw value; this form therefore returns an optional.

```swift
// main.swift — raw value, construction with rawValue, and allCases
print(Weekday.tuesday.rawValue)
print(Weekday(rawValue: 3) == .wednesday)
print(Weekday(rawValue: 9) == nil)
print(Weekday.allCases.count)
```

```
2
true
true
3
```

The first line gives the raw value of the `tuesday` case: because the first case started at `1`, it is `2`. The second line shows that the value constructed with `rawValue: 3` equals `.wednesday`. The third line shows that for `9`, which is the raw value of no case, the result is `nil`; the empty box we saw in the first lesson is here the result of searching for a case, not of an `Int` conversion. The fourth line shows that `allCases`, added by `CaseIterable`, counts three cases.

Here the raw value is a tool for identity and conversion. It is used to convert an integer coming from a network response, a file or a database field safely into a case, and it forces the caller to decide what to do with an invalid value.

A raw value does not have to be an integer. In an enumeration whose type is `String`, the raw value of each case is the case's own name, unless written explicitly. We do the same three operations with a list of planets: reading the raw value, constructing a case from a raw value, and trying to construct from an invalid raw value.

```swift
// main.swift — a String raw value is the case name unless specified
enum Planet: String {
    case mercury, venus, earth
}

print(Planet.venus.rawValue)
print(Planet(rawValue: "earth") == .earth)
print(Planet(rawValue: "pluto") == nil)
```

```
venus
true
true
```

The first line shows that the raw value of the `venus` case is `"venus"` although no value was written. The second line shows that the raw value `"earth"` gives the `.earth` case, and the third line shows that for `"pluto"`, which is not in the list, the result is `nil`. As in the integer example, the reverse direction returned an optional here too: the path from a raw value to a case always carries the possibility of absence.

**TS14.** These measurements are for one enumeration with an `Int` raw value and one with a `String` raw value. Other raw value types (`Double`, `Character`) and the behavior of `Int` cases with raw values written for only some of them were not measured separately.

## Associated Values and Pattern Matching

An associated value works differently from a raw value. A raw value is fixed at definition and is the same in every instance of the same case. An associated value is determined when the case is **constructed**, and each instance carries its own value. `Reading.celsius(21.5)` and `Reading.celsius(30.0)` are the same case but carry different data. To reach what is inside such a value, **pattern matching** with `switch` is used: in the branch of each case, the associated value is bound to a name.

```swift
// main.swift — opening an associated value with pattern matching
let readings = [Reading.celsius(21.5), Reading.label("hot")]
for reading in readings {
    switch reading {
    case .celsius(let degrees):
        print("degrees", degrees)
    case .label(let text):
        print("label", text)
    }
}
```

```
degrees 21.5
label hot
```

The two `Reading` values in the array enter the `switch` in turn. The first selects the `celsius` branch and binds the `21.5` inside it to the name `degrees`; the second selects the `label` branch and binds the string `"hot"` to the name `text`. In each branch the bound name is valid only in the body of that branch, and its type is the type of that case's associated value. The compiler checks that all cases are handled: if a case is skipped, the `switch` is considered incomplete, and a branch for the missing case or a `default` has to be written.

This behavior is the same pattern as the optional of the first lesson. `Optional` is also an enumeration, and its `.some` case carries an associated value; `if let` and `case .some(let value)` inside a `switch` are two spellings of the same matching. This lesson gives a second example of why the box in that lesson behaves the way it does.

When only a single case has to be looked at, writing a `switch` is heavy. `if case` writes the same matching as a single condition: if the case matches, the associated value is bound and the block runs; if it does not match, the `else` branch runs. One more condition can be added with a comma; after the associated value is bound, it is used in that condition.

```swift
// main.swift — looking at a single case with if case
let current = Reading.celsius(18.0)
if case .celsius(let degrees) = current, degrees < 20 {
    print("cool", degrees)
}
if case .label(let text) = current {
    print("label", text)
} else {
    print("not a label")
}
```

```
cool 18.0
not a label
```

The first `if case` matched `current` with the `celsius` case, bound `18.0` to the name `degrees`, and also passed the `degrees < 20` condition after the comma. The second `if case` tried to match the same value with the `label` case, and because there was no match it ran the `else` branch. This is the same behavior as `switch`: when a case does not match, the associated value is never bound and the related name is not in scope.

**TS15.** This measurement is for an enumeration with two cases, each with a single associated value. Cases with several associated values, `indirect` enumerations and branches with a `where` condition were not measured.

## When the Associated Value Is Set Up

An associated value is an expression given when the case is constructed. When `Reading.celsius(stamp.eval(19.0))` is written, the expression `stamp.eval(19.0)` is evaluated once while the case is constructed, and the result is stored inside the case. When it is later read with `switch`, the expression is not computed again; what is read is the value stored in the case. We measure this by reading twice.

```swift
// main.swift — the associated value is evaluated once, when the case is constructed
let stamp = Probe("associated-value")
let reading = Reading.celsius(stamp.eval(19.0))

for _ in 1...2 {
    _ = stamp.use { () -> Double in
        switch reading {
        case .celsius(let degrees):
            return degrees
        case .label:
            return -1
        }
    }
}
stamp.report()
```

```
associated-value: 1 evaluations, 2 uses -> immediately
```

One evaluation, two uses, moment **immediately**. The evaluation took place on the line where `reading` was constructed, before the `use` calls. Both `switch` statements read the same stored value and did not run the expression again. This differs from the raw value: the expression of a raw value never runs, because it is a constant. The expression of an associated value runs once per instance.

The practical result the measurement shows is this: an expensive computation written into an associated value is paid when the case is constructed, and reads need no extra computation. Code that wants the computation done at the moment of reading should use a computed property, not an associated value. The next section measures that property.

**TS16.** This measurement is for an expression that wraps a constant `Double` literal. Cases where the associated value is a function call, or an expression containing another associated value, were not measured separately.

## The Bounding Measurement

A raw value and an associated value are fixed when the case is constructed or in the definition; that is, reading them costs nothing. An enumeration, however, can carry a **computed property** as well as stored values. This property stores no value; it runs its body every time it is read. In the `Sensor` enumeration, the `fahrenheit` property converts the Celsius degrees, carried as an associated value, to Fahrenheit on every read. The conversion expression is marked with a `Probe`, and the property is read twice.

```swift
// main.swift — an enumeration's computed property runs on every read
enum Sensor {
    case reading(Probe, Double)

    var fahrenheit: Double {
        switch self {
        case .reading(let probe, let celsius):
            return probe.eval(celsius * 9 / 5 + 32)
        }
    }
}

let derived = Probe("computed-property-sensor")
let sensor = Sensor.reading(derived, 20)
_ = derived.use { sensor.fahrenheit }
_ = derived.use { sensor.fahrenheit }
derived.report()
print(sensor.fahrenheit)
```

```
computed-property-sensor: 2 evaluations, 2 uses -> on-every-use
68.0
```

Two reads, two evaluations, moment **on every use**. A computed property does not store its result; each time `sensor.fahrenheit` is written, its body runs from the start. The associated value `20` was fixed at construction, but the `68.0` derived from it is computed again on every read. The second line of the output shows that the next read of the same property gives the same result.

This result narrows the lesson's rule. The sentence "an associated value is evaluated once when the case is constructed" is true only for the associated value itself. Every computed property derived from an associated value runs from the start on every read. When the same computation is needed in several places, keeping the result in a name is cheaper than reading the computed property again everywhere.

There is also a limit for raw values, and it cannot be measured, because it does not compile. A raw value must be a constant written in the source. The fragment below tries to assign the return of a function as a raw value and does not compile: the compiler rejects it. The error message said that a raw value has to be written as a constant. The fragment stands here only for explanation.

```swift
func rawOf() -> Int { 3 }
enum Bad: Int {
    case a = 1
    case b = rawOf()   // does not compile: a raw value must be a constant
}
```

This limit shows a second difference between the two kinds of value. An associated value can be any expression evaluated at runtime; a raw value is a constant known at compile time. The expression of a raw value is therefore never evaluated at runtime.

**TS17.** This measurement is for a single computed property derived from two stored values. A computed property that is not read-only (one with a `set`) and the methods of the enumeration were not measured separately. In the rejected raw value fragment only a function call was tried; other forms of expression were not tried.

## Reading the Three Values Together

Three different kinds of value were measured in this lesson, and each fell on a different moment. A raw value is a constant written in the definition; as an expression it never runs at runtime, so no measuring probe can be attached to it. An associated value is an expression given when the case is constructed and is evaluated once per instance; in the measurement this moment came out **immediately**. A computed property stores no value and runs its body on every read; in the measurement this moment came out **on every use**.

Although the three kinds may look interchangeable, they answer different questions. If a code coming from outside has to be converted into a case, a raw value fits, because the reverse direction returns an optional and makes invalid input visible. If instance-specific data has to be carried next to a case, an associated value fits, because different instances of a case can carry different data. If a result derived from the carried data has to be produced at the moment it is needed, a computed property fits, but the price paid on every read has to be counted too.

## Summary

- A raw value is fixed in the definition, and `Weekday(rawValue:)` returns an optional; a value that is not found gives `nil`.
- Pattern matching with `switch` binds the associated value to a name in each branch and checks that all cases are handled.
- An associated value is evaluated once when the case is constructed; reads do not run the expression again.
- A computed property in an enumeration stores no result and runs again on every read.
- A raw value must be a constant known at compile time; a function call cannot be a raw value.
- This lesson's moment: **immediately**. The expression of an associated value is evaluated on the line where the case is constructed.

## Next Step

In this lesson we saw that a property in an enumeration runs on every read. Properties do not belong to enumerations alone: structures and classes also carry stored, computed and observed properties, and there is `lazy`, which defers an expression to the first read. The next lesson measures these kinds of property and when each of them sets up its value.
