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
}