Swift 5.1 Two Quick Tips

The release of Swift 5.1 brought some useful polish to the language with minimal source breaking changes. Some of the bigger improvements like property wrappers and ordered collection diffing take some time to get your head around. Luckily there are also some quick hits that you can start using today.

Implicit returns

Many languages allow you to skip the return statement in a method. For example, a Ruby method returns the value of the last expression evaluated:

# Ruby
class Person
  def greeting
    "Hello"
  end
end

joe = Person.new
puts joe.greeting  // "Hello"

Swift 5.1 allows you to omit the return statement for functions (or closures) which are single expressions. For example, we can rewrite the following:

struct Person {
  func greeting() -> String {
    return "Hello"
  }
}

As this with Swift 5.1:

struct Person {
  func greeting() -> String {
    "Hello"
  }
}

You can only omit the return in Swift when the function is a single expression. So while the following is valid Ruby:

# Ruby
def greeting
  if is_birthday?
    "Happy Birthday!"
  else
    "Hello"
  end
end

You cannot write the same in Swift. Unfortunately, in Swift the if conditional is a statement, not an expression so you need the return keywords:

struct Person {
  var isBirthday = false

  func greeting() -> String {
    if isBirthday {
      return "Happy Birthday"
    } else {
      return "Hello"
    }
  }
}

In this trivial case we can rewrite this as a single expression and again omit the return:

func greeting() -> String {
  isBirthday ? "Happy Birthday" : "Hello"
}

This also works well when the getter of a property is a single expression:

struct Person {
  var age = 0
  var formattedAge: String {
    NumberFormatter.localizedString(from: age as NSNumber,
                                  number: .spellOut)
  }
}

Default values for memberwise initializer

As Swift matures a number of the rough edges of the language are getting smoothed over. This change is another example of that. You probably know that a Swift struct gets a default initializer. For example, given this structure:

struct Country {
  var name: String
  var population: Int
  var visited: Bool
}

The compiler creates an initializer with parameters for each member of the structure:

let place = Country(name: "Antarctica", population: 0, 
                    visited: false)

But what if our structure has default values like this:

struct Country {
  var name: String
  var population: Int = 0
  var visited: Bool = false
}

Unfortunately until Swift 5.1 you couldn’t omit the default values from the initializer. You’d get a compiler error about missing arguments. It’s reasonable to want to use an initializer that assumes the default values like this:

let place = Country(name: "Antarctica")

That now works with Swift 5.1.

Further Details

See the following Swift evolution proposal documentation for more details: