Swift Named Parameters

The rules for naming parameters in Swift functions and methods have changed for the better over the last few releases but still seem to cause confusion. Here is my quick summary updated for Swift 2.1.

External vs Local Names

The key to understanding parameter names in Swift is to remember that parameter names can have both an external and a local name:

  • Local parameter names are used in the body of the function/method
  • External parameter names are used when calling the function/method.

The default rules mean that most of the time you do not need to think too much about external names (at least since Swift 2.1):

  • The external names for all except the first parameter default to the local name
  • You omit the name of the first parameter when calling the function/method (since it does not by default have an external name)

This gives us the default Swift behaviour here illustrated with a function that takes three parameters:

func logMessage(message: String, prefix: String, suffix: String) {
  print("\(prefix)-\(message)-\(suffix)")
}

logMessage("error message", prefix: ">>>", suffix: "<<<")
// ">>>-error message-<<<"

Using External Names

If you want to use an external name for the first parameter or use something other than the local name for the other parameters you can override the defaults, preceding the local name with an external name.

func logMessage(message message:String, 
              withPrefix prefix: NSString,
               andSuffix suffix: NSString) {
  print("\(prefix)-\(message)-\(suffix)")
}

logMessage(message: "QWERTY", withPrefix: "***", andSuffix: "$$$")

Our three parameters now have these external and local names:

  • external: message, local: message
  • external: withPrefix, local: prefix
  • external: andSuffix, local: suffix

Note that unlike local names external names do not need to be unique (though it is probably a good idea).

Initializers

The rules change slightly for an initializer to improve readability. Suppose we have a struct with a simple initializer:

struct DataPoint {
  let x, y: Int
  init(x: Int, y: Int) {
    self.x = x
    self.y = y
  }
}

Swift supplies an external name by default for all parameters of an initializer. This means you need to name all parameters, including the first, when calling an initializer:

let point = DataPoint.init(x: 100, y: 100)

If you want to omit an external name you override it with an underscore:

init(_ x: Int, _ y: Int) {
  self.x = x
  self.y = y
}

This gives us the more concise initializer:

let origin = DataPoint.init(0, 0)

When to use External Names?

Just because you can override the external names does not mean you have to. The Swift Programming Language guide has the following suggestion:

“The use of external parameter names can allow a function to be called in an expressive, sentence-like manner, while still providing a function body that is readable and clear in intent.”

For example, using an external name for the first parameter can make the calling code clearer in some cases:

func findRoute(from from: Location to: Location) {
  // ...
}

findRoute(from: place1, to: place2)

Further Reading