Alex headshot

AlBlue’s Blog

Macs, Modularity and More

Swift - enums

2014, mac, swift

In this episode of the Swift introduction series we’ll be looking at enums in Swift.

Enumerations (aka enums) are found in most programming languages as a means to associate a symbol with set membership over a closed group of alternatives. In some cases, the values associated with an enum are meaningless (e.g. Male, Female) and in other cases they hold useful data (e.g. East might have a value of 90 and NorthEast might have a value of 45).

Traditional languages represented an enumeration always as an alias for an integral value and used sleight-of-hand to replace the value at compile time, like a set of #define constants. Although this worked, it meant that enums could be substituted for one another even when it didn’t make sense (e.g. Male == North).

Swift’s enums are more powerful, and enum types are distinct, even if they represent the same values. As a result, it is not possible to compare two enums for equality unless they are of the same type.

For example, to create a simple enum for representing gender:

Defining a Gender enumeration
1
2
3
4
5
Welcome to Swift!  Type :help for assistance.
  1> enum Gender {
  2.   case Male
  3.   case Female
  4. }

There’s no comparison or ordering between different elements; they are just a property which can be one or the other. The enumeration type can be used as an argument type, return type, or variable type using a dot syntax as with structures:

Using a Gender enumeration
1
2
3
4
5
6
  5> let alblue:Gender = Gender.Male
alblue: Gender = Male
  6> alblue == Gender.Male
$R0: Bool = true
  7> alblue == Gender.Female
$R1: Bool = false

Since Swift knows that the type of the variable is Gender, it is not necessary to supply the type of the enumeration at the point of use. This has exactly the same effect:

Using a Gender enumeration with just the enum type
1
2
3
4
5
6
  8> let alblue:Gender = .Male
alblue: Gender = Male
  9> alblue == .Male
$R2: Bool = true
 10> alblue == .Female
$R3: Bool = false

This is commonly seen when passing in flags or other properties in a Swift function. In particular, most of the existing constants in the Objective-C codebase (such as UIDeviceOrientation) are exposed as Swift enumerations, meaning that just the value can be used (such as .UIDeviceOrientationPortrait).

Enumerations can also store values along with their types as well. For example, in nuclear physics, atoms are made up of Quarks, which can have an associated colour property of Red, Blue or Green. These can be represented as enumerations as follows:

Representing Quarks in Swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 11> enum QuarkColor {
 12.   case Red, Blue, Green
 13. }
 14> enum Quark {
 15.   case Up(colour:QuarkColor)
 16.   case Down(colour:QuarkColor)
 17.   case Charm(colour:QuarkColor)
 18.   case Strange(colour:QuarkColor)
 19.   case Top(colour:QuarkColor)
 20.   case Bottom(colour:QuarkColor)
 21. }
 22> let proton = [
 23.   Quark.Up(colour:.Red),
 24.   Quark.Up(colour:.Green),
 25.   Quark.Down(colour:.Blue)
 26. ]
proton: [Quark] = 3 values {
  [0] = Up = { colour = Red }
  [1] = Up = { colour = Green }
  [2] = Down = { colour = Blue }
}
 27> let neutron = [
 28.   Quark.Up(colour:.Red),
 29.   Quark.Down(colour:.Green),
 30.   Quark.Down(colour:.Blue)
 31. ]
neutron: [Quark] = 3 values {
  [0] = Up = { colour = Red }
  [1] = Down = { colour = Green }
  [2] = Down = { colour = Blue }
}

The values in an enum can also be used in patterns in a switch statement. For example, to represent a suit of cards it’s possible to represent both suits and face values:

Representing cards as enums
1
2
3
4
5
6
7
8
9
10
11
 32> enum Suit {
 33.  case Clubs, Diamonds, Hearts, Spades
 34. }
 35> enum Rank:Int {
 36.  case Two = 2, Three, Four, Five
 37.  case Six, Seven, Eight, Nine, Ten
 38.  case Jack, Queen, King, Ace
 39. }
 40> enum Card {
 41.  case Face(Rank, Suit)
 42. }

In the same way that values like Card.Face(.Ace,.Spades) can be used to create a card, it can be used to match a card as well:

Switching on enums
1
2
3
4
5
6
7
8
9
10
 43> let card:Card = .Face(.Ace,.Spades)
card: Card = Face {
  Face = { 0 = Ace, 1 = Spades }
}
 44> switch card {
 45.   case .Face(.Ace,_): println("Smoke me a kipper")
 46.   case .Face(_,.Hearts): println("♥")
 47.   default: println("Try again")
 48. }
Smoke me a kipper

The use of enums as pattern matchable objects is very useful for fungible data structures, like structs. However enums aren’t expected to be fully fledged objects; rather, they are useful at representing orthogonal states for a particular system; whether it be a quark or a card.


In next week’s episode, we’ll look at how to do more functional programming in Swift. To subscribe to this series, add the Swift tag feed to your reader.