What Is the Meaning of The:In Swift Function Signatures and Why Is There No Comma When It Seems There Should Be One

What is the meaning of the : in Swift function signatures and why is there no comma when it seems there should be one?

The convention, frequently seen in documentation, is a concise way of referring to a function, using only the function name and argument labels.

So consider this function declaration:

func insert(_ objects: [Any], at indexes: IndexSet)

This is

  • a method called insert;
  • the first parameter name is called objects, this parameter has no argument label (designated with the _) and has a type of [Any]; and
  • the second parameter name is indexes, its argument label is at and has a type of IndexSet.

So you call it like so:

insert(someObjects, at: someIndex)

When you call it, you don’t care what the parameter names that are used inside that function, but rather just what the argument labels are. So, the convention when referring to that method in documentation is to omit the parameter names and types and just use the function name and the argument labels, but no comma:

insert(_:at:)

Note, you’d never actually use this syntax in your code. This is just a documentation convention employed to distill long function declarations down to something more manageable and concise:

transition

For more information about argument labels and parameter names, see Function Argument Labels and Parameter Names

Explanation of draw(_:) ios method syntax

1- draw(_:for:)

Implemented to draw the view’s content for printing.

2- draw(_:)

Draws the receiver’s image within the passed-in rectangle.

1- The _ is the argument label and when it exists for a parameter you don't need to pass the parameter name when you call the method

e.x

func goTo(value:Int)  // call goTo(value:5)
func goTo(_ value:Int) // call goTo(5)

2- The colon : separates the parameterName from the parameterType like

paramterName:parameterType

Why do I need underscores in swift?

There are a few nuances to different use cases, but generally an underscore means "ignore this".


When declaring a new function, an underscore tells Swift that the parameter should have no label when called — that's the case you're seeing. A fuller function declaration looks like this:

func myFunc(label name: Int) // call it like myFunc(label: 3)

"label" is an argument label, and must be present when you call the function. (And since Swift 3, labels are required for all arguments by default.) "name" is the variable name for that argument that you use inside the function. A shorter form looks like this:

func myFunc(name: Int) // call it like myFunc(name: 3)

This is a shortcut that lets you use the same word for both external argument label and internal parameter name. It's equivalent to func myFunc(name name: Int).

If you want your function to be callable without parameter labels, you use the underscore _ to make the label be nothing/ignored. (In that case you have to provide an internal name if you want to be able to use the parameter.)

func myFunc(_ name: Int) // call it like myFunc(3)

In an assignment statement, an underscore means "don't assign to anything". You can use this if you want to call a function that returns a result but don't care about the returned value.

_ = someFunction()

Or, like in the article you linked to, to ignore one element of a returned tuple:

let (x, _) = someFunctionThatReturnsXandY()

When you write a closure that implements some defined function type, you can use the underscore to ignore certain parameters.

PHPhotoLibrary.performChanges( { /* some changes */ },
completionHandler: { success, _ in // don't care about error
if success { print("yay") }
})

Similarly, when declaring a function that adopts a protocol or overrides a superclass method, you can use _ for parameter names to ignore parameters. Since the protocol/superclass might also define that the parameter has no label, you can even end up with two underscores in a row.

class MyView: NSView {
override func mouseDown(with _: NSEvent) {
// don't care about event, do same thing for every mouse down
}
override func draw(_ _: NSRect) {
// don't care about dirty rect, always redraw the whole view
}
}

Somewhat related to the last two styles: when using a flow control construct that binds a local variable/constant, you can use _ to ignore it. For example, if you want to iterate a sequence without needing access to its members:

for _ in 1...20 { // or 0..<20
// do something 20 times
}

If you're binding tuple cases in a switch statement, the underscore can work as a wildcard, as in this example (shortened from one in The Swift Programming Language):

switch somePoint { // somePoint is an (Int, Int) tuple
case (0, 0):
print("(0, 0) is at the origin")
case (_, 0):
print("(\(somePoint.0), 0) is on the x-axis")
case (0, _):
print("(0, \(somePoint.1)) is on the y-axis")
default:
print("(\(somePoint.0), \(somePoint.1)) isn't on an axis")
}

One last thing that's not quite related, but which I'll include since (as noted by comments) it seems to lead people here: An underscore in an identifier — e.g. var _foo, func do_the_thing(), struct Stuff_ — means nothing in particular to Swift, but has a few uses among programmers.

Underscores within a name are a style choice, but not preferred in the Swift community, which has strong conventions about using UpperCamelCase for types and lowerCamelCase for all other symbols.

Prefixing or suffixing a symbol name with underscore is a style convention, historically used to distinguish private/internal-use-only symbols from exported API. However, Swift has access modifiers for that, so this convention generally is seen as non-idiomatic in Swift.

A few symbols with double-underscore prefixes (func __foo()) lurk in the depths of Apple's SDKs: These are (Obj)C symbols imported into Swift using the NS_REFINED_FOR_SWIFT attribute. Apple uses that when they want to make a "more Swifty" version of an (Obj)C API — for example, to make a type-agnostic method into a generic method. They need to use the imported API to make the refined Swift version work, so they use the __ to keep it available while hiding it from most tools and documentation.

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.

How to tell Swift which function signature to use between default optionals

Quick Answer for your issue: Xcode BUG

First of all, as your screenshots show, it's a bug. (try removing driven data or restarting stuff to make it work). The following is the answer to your question.



Explanation: How to tell the compiler to use which method signature

Swift infers the function signature based on the used Types in the expression. So imagine this:

class ViewController { }
class UIViewController { }

func instantiateInitialViewController() -> UIViewController? {}
func instantiateInitialViewController() -> ViewController? {}

So calling this would be ambiguous use of instantiateInitialViewController():

let theController = instantiateInitialViewController()

The solution for this is to tell the compiler what is the expected type explicitly:

let theController: ViewController? = instantiateInitialViewController()
let theOtherController: UIViewController? = instantiateInitialViewController()

The new instantiateInitialViewController return type is a protocol (ViewController) that constrained to UIViewController. So it should infer the type and have no logical difference from the old one. So just keep calm and just let it infer ;)

Is there a way to use functions with same names but different return types?

You cannot define two functions with identical parameter types without creating an ambiguity, but you can call a function returning a value as if it were Void. This generates a warning, which you can silence by designating your function result discardable:

@discardableResult
public mutating func replaceSubstringInRange(_ range: CountableClosedRange<Int>, withString string: String) -> String {
}

What is function signature if parameters are split by comma rather than colon when invoked?

You said:

[I am] a bit confused about how function stringWithFormat is defined or its signature.

If you command-click on stringWithFormat in your code, it will take you directly to its declaration (and you can hit the "back" button to return to your code). Anyway, stringWithFormat is defined as follows:

+ (instancetype)stringWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1,2);

Those ellipses (...) indicate that it is a "variadic function", that it takes a variable length list of parameters separated by commas. This is a C programming pattern which is also incorporated into Objective-C.

In case you're wondering, that NS_FORMAT_FUNCTION is a hint to the compiler that the first parameter (1) is a printf-style format string (or more accurately, slightly richer rendition that NSString uses), and that the parameters starting at the second parameter (2) should match up with what appears in the format string. That lets the compiler check your list of parameters to see if it matches the format string.

The fact that they felt compelled to add this special logic for printf-style parameters is actually a clue to the deeper problem of variadic parameters: With the exception of printf-style case, it's hard to ensure that the parameters passed to the function match what the function was expecting.

As a result, you will generally only see variadic method declarations where the number of parameters being passed to a method is variable and that it has a printf-style format string. (Technically, you can use it in any situation with variable number of parameters, but in those situations there are generally better approaches, e.g. pass an array. In fact, if you look at Apple's newer Cocoa API, where they need variable number of parameters, they generally pass an array rather than using the variadic patterns that you'll see in some of the older API.)

So, you're right, we generally invoke a method like so:

[objectName funcName:firstValue secondParameterName:secondValue thirdParameterName:thirdValue];

But, in special cases, you can employ variadic functions.

Swift: Split comma-separated strings, but not if comma enclosed in single quotes

What about separating the string by single quotes and removing elements containing a single comma and a space afterwards?

Note that you should remove the first/last element of the result, since the input starts and ends with a single quote and that produces an empty element after separating.

var result = myString.components(separatedBy: "'").filter { 
$0.trimmingCharacters(in: .whitespaces) != ","
}

result.removeLast()
result.removeFirst()


Related Topics



Leave a reply



Submit