I just wanna tell you how I'm feeling

Rick Astley

An Introductory Romp in The Garden of Enumerations

A little known fact* is that the inspiration behind the 1987 chart topper “Never Gonna Give You Up” came in the form of assembly code delivered to Rick Astley while in a feverish dream state. The prevailing message of this lucid epiphany came as an enumeration:

 *possibly made up

enum ThingsRickAstleyWontDo {
 case GiveYouUp
 case LetYouDown
 case RunAround
 case DesertYou
 }

// Implementation

// assign the type ThingsRickAstleyWontDo to the variable
var heIsNeverGoingTo = ThingsRickAstleyWontDo.GiveYouUp    

heIsNeverGoingTo = .LetYouDown
heIsNeverGoingTo = .RunAround
heIsNeverGoingTo = .DesertYou

Out of the box Swift comes with a collection of built in data types for your declarative pleasure; Int, String, Double, Array etc… but Swift also allows you to define your own custom data types.

Enums are a custom data type consisting of a finite set of named values (members) which may themselves have values (associated values). Any time you’re modeling something with a finite set of outcomes the enum bell should start dinging. Examples include: coin toss, dice roll, days of the week, number of planets, choice of e.coli riddled meat at Chipotle – all great candidates for enums.

Raw Values > Raw Food Diet

Another wonderful feature is the ability to access raw values – underlying data types assigned to each member. Note these will all be of the same type (so all integers, or all strings etc…).

enum CelloString: Int {
    case CString = 1
    case GString
    case DString
    case AString
}

var string = CelloString(rawValue: 3)  // = .Dstring
// Or
var anotherString = CelloString.AString.rawValue   // = 4
// can also retrieve raw value:
string?.rawValue   // = Optional(3)

Note that because not all raw values have associated members the type of string is optional CelloString? not CelloString

Associated Values

Beyond raw values every member of your enum can have multiple associated values, which can be of different types for each member. So let make some beats!

enum DrumPart {
    case KickDrum (brand: DrumBrand, size: Int)
    case SnareDrum (brand: DrumBrand, size: Int)
    case HiHats (brand: CymbalBrand, size: Int)
    case Cymbal (brand: CymbalBrand, cymbalType: CymbalType, size: Int)
    case Tom (brand: DrumBrand, size: Int)
}

enum CymbalBrand {
    case Zildjian
    case Sabian
    case Paiste
}

enum CymbalType {
    case Crash
    case Ride
    case China
    case Splash
}

enum DrumBrand {
    case DW
    case Pearl
    case Yamaha
}

let myKick = DrumPart.KickDrum(brand: .Pearl, size: 22)
let mySnare = DrumPart.SnareDrum(brand: .Pearl, size: 14)
let myHats = DrumPart.HiHats(brand: .Sabian, size: 16)
let myFloorTom = DrumPart.Tom(brand: .Pearl, size: 16)

let myDrumKit: [DrumPart] = [myKick, mySnare, myHats, myFloorTom]  // an array of custom type DrumPart

This model might lend itself to an app where the user’s creating a virtual drum kit from a finite choice of parts.

Methods Inside Enums

Enums can be further juiced up by adding methods to them. The example below shows a way of organizing the possible values (in Hertz) used as the tuning reference in a music app.

enum TuningReferenceHz: Int {
    case Baroque = 415
    case Standard = 440
    case NYPhil = 442
    case ViennaPhil = 443
    case BerlinPhil = 445
    
    func description() -> String {
        switch self {
        case .Baroque: return "\(self) tuning was more commonly used in the 17th century"
        case .Standard: return "\(self) tuning was adopted as the standard in western music in the early 19th century"
        case .NYPhil: return "The New York Philharmonic tunes to \(self.rawValue)Hz"
        case .ViennaPhil: return "The Vienna Philharmonic tunes to \(self.rawValue)Hz"
        case .BerlinPhil: return "The Berlin Philharmonic tunes to \(self.rawValue)Hz"  
        }
    }
}

// use these values elsewhere:
let myAppTuningPitch = TuningReferenceHz.Baroque.rawValue    // tuning now set to A = 415Hz

// give the user a brief description of the tuning standard
let descriptionLabel = TuningReferenceHz.BerlinPhil.description()

Safety First!

Writing “stringly” typed code is a quick way to get approved for a mortgage in Crashville.

“Safety” is term frequently associated with Swift. Enums are a great example of how you can make your code safer. In the above example the description method uses a switch statement to return a string. Because it’s switching on an enum (self) the  compiler wont let you sleep in your nice warm bed at night until you’ve accounted for all of enumeritastical* possibilities. This also leads to more maintainable code. For example, let’s say further down the road you’d like to add in other tuning standards to the app. There’s now a central place to make this change plus if you’ve structured the rest of code nicely you’ll get a warm cozy blankey of compiler checks before you release an update that takes someone’s eye out**.

 * possibly not real word
 ** worst case scenario?

In Summary

  • Enums are custom data types
  • They are ideal for modeling situations with finite outcomes / possible values
  • Great for use within switch statements as the compiler will check that the switch is exhaustive and prevent error resulting from stringly typed code
  • Each enum member has a raw value (pre-populated) / can have associated values
  • Their functionality can be extended by adding method inside

Find a playground containing these examples on GitHub here.

Leave a Reply