[I filed this as Radar #31462992. I might be overthinking things — this is a little like quibbling over whether something's a metaphor or a simile — but word choices matter to me. You should see how I overthink my variable names.]
In "The Swift Programming Language (Swift 3.1)" the terms "argument label" and "parameter name" are misnomers. I have suggestions for solutions.
Misnomers
Programmers often use the terms "parameter" and "argument" interchangeably, but they have distinct meanings.
A parameter is a specification of a value that a function expects to be passed to it. It is an inherent part of the function signature. A programmer who calls the function needs to understand this specification so they can call the function correctly.
An argument is an actual value that is passed to a function when the function is called. The programmer who implements the function needs the argument to have a name so their code can reference that value.
The way the Swift documentation uses these terms is the reverse of the above meanings. Consider this function:
func wave(toward person: Person) { print("Hello, \(person).") } |
func wave(toward person: Person) { print("Hello, \(person).") }
According to the docs, "toward" is the argument label and "person" is the parameter name. This is backwards, because the "toward" is the part that the caller of the function must get right, whereas "person" is a local name that's used in the implementation of the function, and that doesn't matter to the caller at all. The word "toward" is part of the function signature, whereas the word "person" isn't.
To drive this point home, imagine that wave(toward:) is a method of a class. Overrides of the method can replace "person" with whatever name they like, or leave out the separate name altogether:
// class GenericWaver
func wave(toward person: Person) { print("Hello, \(person).") }
// class FriendlyWaver
override func wave(toward guest: Person) { print("Welcome, \(guest)!") }
// class HostileWaver
override func wave(toward enemy: Person) { print("Get lost, \(enemy)!") }
// class LazyWaver
override func wave(toward: Person) { print("Whatever, \(toward).") } |
// class GenericWaver
func wave(toward person: Person) { print("Hello, \(person).") }
// class FriendlyWaver
override func wave(toward guest: Person) { print("Welcome, \(guest)!") }
// class HostileWaver
override func wave(toward enemy: Person) { print("Get lost, \(enemy)!") }
// class LazyWaver
override func wave(toward: Person) { print("Whatever, \(toward).") }
If we use the conventional meaning of "parameter" and "argument", then in all four methods, "toward" is part of the parameter description, whereas "person", "guest", "enemy", and "toward" are different names for the same argument — contrary to the terminology used in the docs.
Possible solutions
Fixing this misnaming is not quite as simple as switching the terms "parameter name" and "argument label", because those terms actually make two distinctions:
- parameter vs. argument
- label vs. name
Consider again the first "wave" function above. Linguistically speaking, what's happening is that the prepositional phrase "toward person" is broken up so that the noun "person" can be referenced in the function implementation. The preposition "toward" is used as a cue to the programmer calling the function, as a signpost, a kind of fill-in-the-blank. The term "label" makes sense. It's analogous to a label in a form-based user interface:
By this reasoning, the most accurate correction would be to use the terms "parameter label" and "argument name".
If I only cared about formal precision, I'd leave it at that, but these names feel heavy to me, and still potentially confusing.
Another solution would be to use the wording Daniel Steinberg uses in A Swift Kickstart: every parameter has an "external name" and an "internal name". This approach gets rid of the label-vs.-name distinction, and this simplification buys increased clarity — the distinction between "external" and "internal" is immediately clear. As a bonus, the rest of the documentation would be a little more free to use "parameter" and "argument" interchangeably without risking confusion. That might or might not be a good thing, depending on your taste.
Yet another solution would be instead to get rid of the parameter-vs.-argument distinction, and call the things "argument label" and "argument name".
One more thing. If you choose to have different external and internal names, the docs describe the external name as something that you add to the left of the internal name. To my mind, it's the other way around: I'd suggest describing the internal name as something you insert after the external name. The difference is subtle, but to me it's meaningful, because the external name is primary and essential, whereas the separate internal name can be thought of as an optional implementation detail. (This is a bit of an oversimplification of the thought process behind having an internal name, but I think the general point still stands.)