The difference between arguments and parameters isn't difficult to understand. Most developers use the term argument and parameter interchangeably because they assume they are the same or they are not sure what the difference is. Let's take a moment to understand what sets arguments apart from parameters in Swift.

Arguments and Parameters in Swift

Fire up Xcode and create a playground by choosing the Blank template from the iOS > Playground section.

What Is the Difference between Arguments and Parameters in Swift

Remove the contents of the playground and add an import statement for the UIKit framework.

import UIKit

We declare a function with name writeImage(_:to:). The function defines two parameters, image of type Data and url of type URL.

import UIKit

func writeImage(_ image: Data, to url: URL) {
    // Write Image to Disk
}

We invoke the function by passing a Data object as the first argument and a URL object as the second argument.

writeImage(Data(), to: .cachesDirectory)

Did you notice how I used the terms arguments and parameters? Let's dissect the writeImage(_:to:) function to understand what arguments and parameters are.

Parameters in Swift

A function or method in Swift can take input by defining one or more parameters. A function or method defines zero or more parameters. A function or method that doesn't take input simply doesn't define any parameters. That makes sense. Right?

The writeImage(_:to:) function defines two parameters. A parameter always has a name and a type. The first parameter of the writeImage(_:to:) function is of type Data and its name is image. The second parameter of the writeImage(_:to:) function is of type URL and its name is url.

Arguments in Swift

The arguments of a function or method are the values you pass it when it is invoked. In the example, the arguments of the writeImage(_:to:) function are a Data object and a URL object. The order in which the arguments are passed to the function or method is defined by the parameter list.

Argument Labels

I wrote earlier that the parameters of the writeImage(_:to:) function are named image and url. The name of a parameter is the name you use in the body of the function or method to refer to the value of the parameter.

A function also defines argument labels in addition to parameter names. The label of an argument is used when the function or method is invoked. Let's revisit the writeImage(_:to:) function. The label of the second argument is to. The first argument doesn't have a label hence the underscore. An underscore indicates that the argument doesn't have a label and that is why the Data object we pass to the writeImage(_:to:) function isn't preceded by an argument label.

writeImage(Data(), to: .cachesDirectory)

Argument Labels and Parameter Names

You may be wondering why functions and methods define argument labels and parameter names. Why do we need both? You could rewrite the writeImage(_:to:) function as follows.

func writeImage(image: Data, url: URL) {
    // Write Image to Disk
}

writeImage(image: Data(), url: .cachesDirectory)

This is perfectly valid Swift, but note that the rewritten writeImage(image:url:) function still defines argument labels and parameter names. The only difference is that the labels and names are identical. The argument label and the parameter name of the first parameter are both image.

Why are the argument labels and the parameter names different in the original declaration of the writeImage(_:to:) function? A function or method at the call site should be readable because that makes your code readable and easier to understand. That is why the first argument has no label and the label of the second argument is to. It makes the method call easy to read and understand. The function writes an image to the location the URL points to.

writeImage(Data(), to: .cachesDirectory)

We don't define a label for the first argument because the name of the function, writeImage(_:to:), makes that unnecessary. We could rewrite the function as follows if you prefer that style.

write(image: Data(), to: .cachesDirectory)

What Is the Purpose of Parameter Names?

I still haven't explained why we need parameter names in addition to argument labels. The label of an argument improves the readability of the function or method when it is invoked, but the label of the argument is often not ideal to reference the value of the parameter in the body of the function or method. Take a look at this example from the UITableViewDataSource protocol.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(
        withIdentifier: NoteTableViewCell.reuseIdentifier,
        for: indexPath
    )

    // Configure Cell
    // ...

    return cell
}

Let's focus on the second parameter of the tableView(_:cellForRowAt:) method. The argument label of the second parameter, cellForRowAt, makes the method easy to read and understand when it is invoked, but it is not ideal in the body of the method. It would be confusing if we were to use cellForRowAt in the body of the method. The name of the parameter, indexPath, makes it clear the parameter is of type IndexPath.

Building Type-Safe APIs in Swift

I very much like that Swift offers developers the flexibility to label arguments and name parameters. By carefully choosing the labels of arguments and names of parameters, you can build APIs that are readable and intuitive to use. We take a closer look at this topic in Building Type-Safe APIs in Swift.