Swift 3 First Parameter Names

Swift 3 first parameter names

Yes, this is right. Swift is fixing a language inconsistency this way (this was always required for initializers).

If you don't want to use the external parameter name, just remove it explicitly:

func frobnicate(_ runcible: String) { 
print("Frobnicate: \(runcible)")
}

You can read the full rationale in Swift Evolution 0046

Why is a function's first parameter name in Swift not required when calling?

As others have said, it's a style issue originating with Objective-C.

To understand why someone would want this style, consider a modification of your example:

func say(greeting: String) {
print("\(greeting)")
}

which you would call like this:

say("Hello!")

When you look at the names you're using, there's arguably some information missing. With a function called say(), you might reasonably think that this is a function to let you say anything at all. But when you look at your parameter name, it's pretty clear that this is a function for saying a greeting, not for saying anything.

So Objective-C would prefer you to write it like this:

func sayGreeting(greeting: String) {
print("\(greeting)")
}

which you would call like this:

sayGreeting("Hello!")

and it is now clear that you are saying a greeting. In other words, the function name itself is more clearly describing what you are doing. For this reason, sayGreeting("Hello!") is preferable to say(greeting: "Hello!") because the key thing that a function does should be described by its name, not relegated to a parameter name and given secondary importance.

But this rationale only really works for the first argument. Suppose you want to add a name, as you have done. In a language like C, where you have no external parameter names at all, you might write:

void sayGreetingToName(char * greeting, char * person) { ...

and call it like:

sayGreetingToName("Hello", "Dave");

which is OK, but starts to break apart quickly when you have overloaded functions or default values, neither of which you have in C. If you wanted to write:

func sayGreetingToName(greeting: String, name: String? = nil) {
if let name = name {
print("\(greeting), \(name)!")
}
else {
print("\(greeting)!")
}
}

then calling it as:

sayGreetingToName("Hello", "Dave")

would look basically OK, but:

sayGreetingToName("Hello")

looks ridiculous, because the function name says you're providing a name, but you're not.

So instead, if you write:

func sayGreeting(greeting: String, toName: String? = nil) {
if let name = toName {
print("\(greeting), \(name)!")
}
else {
print("\(greeting)!")
}
}

you can call it in two ways:

sayGreeting("Hello")
sayGreeting("Hello", toName: "Dave")

and everything looks perfectly clear.

So to summarize, the idea behind this style of writing is that the function name itself should contain any information that the name of the first parameter contains, but that it doesn't make sense to extend this to subsequent parameters. So by default the first has no external name, but the rest do. The function is all about saying a greeting, all the time, so that should be inherent in the name of the function (and therefore not duplicated by insisting on the external name of the first parameter) but it may or may not be about saying it to a particular name, so that information should not be in the function name.

It also enables you to essentially read a function call as if it were English, because the names and the parameters are now approximately in the right order for you to do that:

sayGreeting("Hello", toName: "Dave")

Say (the) greeting, "Hello", to (the person with) name "Dave"

It's quite a nice style, once you get used to it.

Using Function Parameter Names in Swift

This is to follow an convention we were all used to from Objective-C, where the name of the first parameter is combined with the method name. Here's an example:

- (void)incrementByAmount:(NSInteger)amount
numberOfTimes:(NSInteger)times
{
// stuff
}

You could call the method like:

[self incrementByAmount:2 numberOfTimes:7];

And it feels more natural to read by incorporating the name of the parameter into the method's name. In Swift, you can achieve the same with the following:

func incrementByAmount(amount: Int, numberOfTimes: Int) {
// same stuff in Swift
}

And call the method like:

incrementByAmount(2, numberOfTimes: 7)

If you don't want to use this convention, Swift gives you the ability to be more explicit and define separate internal and external parameter names, like so:

func incrementByAmount(incrementBy amount: Int, numberOfTimes: Int) {
// same stuff in Swift
// access `amount` at this scope.
}

You can call the method like this:

incrementByAmount(incrementBy: 2, numberOfTimes: 7)

Why does Swift require parameter names if it also requires argument order?

TL;DR

To help understand the answer to your question, you first have to understand that unlike other languages which support named arguments, in Swift, you are not actually seeing the argument names at all. You are seeing what are known as outward-facing labels. While they often do match the argument names, that is merely a coincidence/convenience. They are still very much separate things, with an entirely different set of rules, and understanding that difference helps explain the answer to your question.

That's why in Swift, when you're referring to the call site, don't think about argument names at all. Think of what you're seeing as words which add clarity at the call site by helping it read more like a sentence, and just as you can't randomly reorder words in a sentence, you shouldn't be able to randomly reorder those labels either.

The Rules

A simple set or rules describing the above can be summed up as follows...

  • Argument labels (external) are meant make sense only at the call site so it's clear what you are passing. As such they may function more in a 'grammar' fashion than an 'identifier' fashion (e.g. the function add(4, to: 3) uses the label 'to:' for the second argument, and no label at all for the first argument as the function name itself completes the grammar.) Also, labels do not have to be unique as they are also bound by ordinal position.

  • Argument names (internal) are meant to make sense only in the context of the function/method's internal body. The above function may be written as add(_ valueA: Int, to valueB: Int) which uses valueA and valueB only within the function's implementation.

  • If such a name makes sense in both contexts, you only need to specify the argument name, and it will implicitly use that same name for the label (e.g. someFunc(a: Int) is the equivalent of someFunc(a a: Int))

I highly recommend checking out Swift.org's API Design Guidelines as it goes into much more detail about why these decisions were made.

The Details (e.g. the reason)

In most languages, there is no concept of outward-facing labels. You simply specify a function's argument values by ordinal position, usually separated by a comma.

Now in some languages, like C#, in addition to specifying argument values ordinally, you can also/instead specify them by argument name. If you are specifying all arguments by name, it seemingly logically makes sense to be able to specify them in whatever order you want, but there are no requirements to use names so you can mix and match with ordinals.

But if you can do that, what happens when you specify some ordinally and some by name? Now you're forced to put the named ones at the end because if you didn't, how would it know the position of the unnamed arguments? Or more confusing, what happens if you specify an argument value in the third position but you also specify that same argument by name later on? It can be confusing.

In contrast, Swift strives to not only be much more consistent in its calling conventions, but it also strives to be a self-documenting language with a focus on clarity at the point of use (i.e. the call-site). As such, Swift added the concept of external/outward labels which default to being required, but it allows you to make them optional if it makes sense. And if you don't explicitly specify a label for your argument, the label is implicitly set to the same name as the argument, but again, they are still very different things.

Now as to the why this is a good thing, let's look at some examples.

Examples

Let's start with a language like C# that does let you reorder named arguments.

var result = multiplyValues(valA: 20, valB: 5)

Since you can reorder it, you can write this as well...

var result = multiplyValues(valB: 5, valA: 20)

Now in Swift, what you use at the call site aren't argument names, they are labels to help in the overall context of the signature itself.

Consider this slightly more complex function definition...

func multiply(value: Int, by factor: Double, thenAdd addlAmount: Int){}

When called, it reads like this...

let result = multiply(value: 20, by: 1.5, thenAdd: 5)

Isn't that much clearer than the C# example? But it's important to note that 'by' is not the argument name, but rather a label that makes sense given its position in the call. The actual, underlying argument is called 'factor' and that's what's used inside the body of the function's implementation.

Following the Swift design guidelines, one may even make the first argument's label optional, which now reads like this...

let result = multiply(20, by: 1.5, thenAdd: 5)

Again, it's incredibly clear what's going on, almost reading like a sentence.

Now imagine if you didn't use those labels and just used the argument names. Now the names matter in the external context. For instance, look at this

let result = multiply(value: 20, addlAmount: 5, factor: 1.5)

Clarity starts to get obscured. Are you multiplying 20 by 1.5 then adding 5, or are you multiplying 25 by 1.5? Is the answer 35 or 37.5?

And what if you then used the external names/labels? Now it's even worse!

let result = multiply(by: 1.5, thenAdd: 5, 20)

What the heck is going on?

When you reorder them in this way, it's not exactly clear what you're multiplying by 1.5, because if this is in an entity (struct, class, etc.) it could be easily mistaken that you're multiplying the implicit self by 1.5 (i.e. self.multiply(by:)), then there's some rando parameter 20 at the end without context. Again, it's not clear.

Of course, naturally you may respond 'But that's with an optional label! The order shouldn't matter if and only if all labels have to be specified.' but now you're cluttering up the rules and breaking consistency for a single, specific use-case.

Perhaps a more pertinent question is what do you actually get with that one-off use-case? With all these up-sides of the existing rules, what's a down-side? What are you not able to do by not allowing a random order?

It's the above aversion to inconsistency that led Swift to introduce a breaking change in earlier versions of Swift where the first argument's label wasn't required even if you specified one. It implicitly added a _ if you will. But why should that first argument get special treatment when compared to the others? The answer... it shouldn't! All that did was confuse people, so they changed it in a future version because again, consistency is more important than cleverness, even over introducing a breaking change.

Argument Names have to be unique. Label names do not.

Since label names are meant to offer clarity at the call site, helping it read more like a sentence, it is possible to use the same label more than once since the order is also important.

Argument names however must be unique because they need to coexist within the implementation.

Here's a example demonstrating this. Note how the label 'and' is used twice, but the argument names 'a', 'b' and 'c' must be unique...

func add(_ a: Int, and b: Int, and c: Int) -> Int {
return a + b + c
}

let result = add(1, and:2, and:3)

print(result)

To Sum Up...

External-facing labels should only make sense at the call site and should strive to complete the grammar of a sentence. Argument names however should only make sense in the context of a function's implementation.

Follow those simple guidelines and it will become very clear what should go where and in what order, and why it's a good thing that you can't simply reorder your arguments at the call site.

Swift: Why necessary to omit name of first parameter, but not subsequent parameters in function calls

Because the naming convention for Objective-C (see here) and Swift is to end your method name by the name of your first argument:

func greetPersonNamed(name: String, onDay day: String) -> String {
return "Hello \(name), today is \(day)."
}

greetPersonNamed("Anna", onDay: "Tuesday")

If you prefer to write the name of the first argument, you can do it like so:

func greet(name name: String, day: String) -> String { /* ... */ }
greet(name: "Anna", day: "Tuesday")

The first name refers to the external name, the second one is the one used inside your method.

EDIT

The naming guidelines for Swift 3 have been released (see here) and they differ from the ones used with Objective-C.

The name of the first argument should not be included in the method name. The external name of the first parameter can be omitted if the function intent is clear. Otherwise you should name it.

Let's say you can greet persons and pets. In that case, you should add an external name for the first argument:

func greet(person name: String, day: String)
func greet(pet name: String, day: String)

greet(person: "Anna", day: "Tuesday")

If you can only greet persons, then you can ommit it:

func greet(name: String, day: String)
greet("Anna", day: "Tuesday")

What's the _ underscore representative of in Swift References?

Both answers were correct but I want to clarify a little bit more.

_ is used to modify external parameter name behavior for methods.

In Local and External Parameter Names for Methods section of the documentation, it says:

Swift gives the first parameter name in a method a local parameter name by default, and gives the second and subsequent parameter names both local and external parameter names by default.

On the other hand, functions by default don't have external parameter names.

For example, we have this foo() method defined in class Bar:

class Bar{
func foo(s1: String, s2: String) -> String {
return s1 + s2;
}
}

When you call foo(), it is called like bar.foo("Hello", s2: "World").

But, you can override this behavior by using _ in front of s2 where it's declared.

func foo(s1: String, _ s2: String) -> String{
return s1 + s2;
}

Then, when you call foo, it could be simply called like bar.foo("Hello", "World") without the name of the second parameter.

Back to your case, runAction is a method because it's associated with type SKNode, obviously. Thus, putting a _ before parameter action allows you to call runAction without an external name.

Update for Swift 2.0

Function and method now work the same way in terms of local and external argument name declaration.

Functions are now called by using external parameter name by default, starting at 2nd parameter. This rule only applies to pure Swift code.

So, by providing an _ in front of a function, the caller won't have to specify external parameter name, just like what you would do for a method.

Swift 3: Why symbol _ is added before sender in parameters of action?

The other answers (one of which has been deleted) covered what the _ means: it eliminates the keyword when you call the method.

However, your question is specifically about “attaching actions to ViewController”.

Methods that have the @IBAction attribute can be connected to controls in your storyboard (or xib). That means the name of the method will be stored, as a string, in the storyboard, and it will be called using the Objective-C message sending system. So the exact name, and how the name is translated to Objective-C, matters very much here.

If you declare the method func methodName(sender: UIButton), then its Objective-C name is methodNameWithSender:.

If you declare the method func methodName(_ sender: UIButton), then its Objective-C name is methodName:.

Both iOS and macOS have something called the “responder chain”, which lets the system search for an object (a “responder”) that can handle an action. You can connect the controls in your storyboard to the First Responder (at the top of the document outline) to have the system do this. Most commonly you do this with menu items in macOS, but there are other uses.

Anyway, there are some standard actions like cut:, copy: and paste:. For example, you would set your Cut menu item's action to send cut: to First Responder. And if you want to implement the cut: method in your view controller, it is critical that its name (when translated to Objective-C) be precisely cut:, and not cutWithSender:. If it's named cut:, the system will find it when searching the responder chain, but if it's named cutWithSender:, the system will not find it and you will wonder why your menu item doesn't work.

Xcode knows this, so it always creates action methods of the form @IBAction func action(_ sender: UIButton), omitting the keyword from the argument, in case you are implementing an action that needs to be found by searching the responder chain.

In Swift 3, every argument to a method has a keyword by default, including the first argument. Back in Swift 2, the first argument did not have a keyword by default, so the _ on the first argument was redundant in Swift 2 (and would generate a compiler warning). That is why Xcode 8 (Swift 3) puts in the _ but Xcode 7 (Swift 2.2) did not.

That is also why your toggleButtons example worked in Xcode 7.



Related Topics



Leave a reply



Submit