Swift Switch And If Expressions

Swift 5.9 introduced a change that allows you to use if and switch statements as expressions. There are some limitations but it can still be useful.

Switch and If Expressions

I feel like I’m late to the party but Swift 5.9 added a useful feature to if and switch statements. If you can stay within some limitations (see below) you can use them as expressions whose value you can return, or assign to a variable.

Here’s an example I had this week. I have an enum modelling the state for a workflow to read, process, and export a file. Some of the states have an associated URL for the input file:

enum State {
  case idle
  case choosingInputFile(URL?)
  case inputReady(URL)
  case exporting(URL)
  case choosingOutputFile(URL, Document)
}

I wanted to compute the last path component of the URL when available or default to “Not set”. I could write something like this:

var importPath: String {
  var path = "Not set"
  switch state {
    case .inputReady(let url): path = url.lastPathComponent
    case .exporting(let url): path = url.lastPathComponent
    case .choosingOutputFile(let url, _): path = url.lastPathComponent
    case .choosingInputFile(let url): 
      if let url {
          path = url.lastPathComponent
      }
    default: break
  }
  return path
}

Using the switch as an expression (that returns a String?) allows me to avoid the temporary path variable:

var importPath: String {
  let value: String? = switch state {
    case .inputReady(let url): url.lastPathComponent
    case .exporting(let url): url.lastPathComponent
    case .choosingOutputFile(let url, _): url.lastPathComponent
    case .choosingInputFile(let url): url?.lastPathComponent
    default: nil
  }
  return value ?? "Not set"
}

An example, using an if statement to test for the exporting state:

let isExporting = if case .exporting = state {
  true
} else {
  false
}

See Swift If Case Let if the if-case syntax is confusing.

Limitations

There’s an important limitation:

Each branch of the if, or each case of the switch, must be a single expression.

That does somewhat limit the usefulness but does match the rules for when we can omit the return keyword.

Also note that the if statement must include an else and return the same type from all branches. You may need to specify the type when the compiler needs some help:

let value: String? = if isExporting == true {
  "Yes"
} else {
  nil
}

Learn More