My music app has another type that needs Equatable conformance, FlowChangeKind. Hint: enums without associated values automatically conform to Equatable.

  enum EndingDirection : String {
    case start, stop, discontinue
  }

  enum RepetitionDirection : String {
    case forward, backward
  }

  enum FlowChangeKind {
    case repetition(RepetitionDirection)
    case ending(EndingDirection)
    case dalsegno, coda, segno
  }

Write the code necessary to add Equatable conformance to FlowChangeKind.

Solution

First, we provide the required operator function in global scope:

  func ==(lhs:FlowChangeKind, rhs:FlowChangeKind)->Bool {
    switch (lhs, rhs) {
    case (.dalsegno, .dalsegno):
      return true
    case (.coda, .coda):
      return true
    case (.segno, .segno):
      return true
    case (.repetition(let lhsDirection), .repetition(let rhsDirection)):
      return lhsDirection == rhsDirection
    case (.ending(let lhsDirection), .ending(let rhsDirection)):
      return lhsDirection == rhsDirection
    default:
      return false
    }
  }

  extension FlowChangeKind : Equatable {
  }

Here, we've used the powers of switch to match both flow changes simultaneously. Notice that I'm switching on a tuple of the lhs and rhs, instead of one or the other. That's some of the cool pattern-matching behavior switch has.

Next, conformance is added in an extension.

As a side note, some consider this particular solution to be less safe, because I could have forgotten a valid case, the default being the red flag. I can re-write the switch like this:

  func ==(lhs:FlowChangeKind, rhs:FlowChangeKind)->Bool {
    switch (lhs, rhs) {
    //matches
    case (.dalsegno, .dalsegno):
      return true
    case (.coda, .coda):
      return true
    case (.segno, .segno):
      return true
    case (.repetition(let lhsDirection), .repetition(let rhsDirection)):
      return lhsDirection == rhsDirection
    case (.ending(let lhsDirection), .ending(let rhsDirection)):
      return lhsDirection == rhsDirection
    //mismatches
    case (.dalsegno, _):
      return false
    case (.coda, _ ):
      return false
    case (.segno, _):
      return false
    case (.repetition(_), _):
      return false
    case (.ending(_), _):
      return false
    }
  }

to make sure that I've exhaustively considered both the matching and mismatching cases.