When Calling a Function in Swift, What Does Each Part Mean

How do I interpret a Swift function declaration?


internal is the scope?

This is an access modifier. It means that only code in the same module can see/call this symbol.

internal is implicit if you leave it off, and has meaning primarily for when you're making frameworks — an app that links a framework can see only the framework's public symbols, but code within the framework can see other internal symbols in the framework. (And code in one type within the framework can't see private symbols inside another type.)

func is a keyword that declares method/functions?

Yes. In Swift, a "method" is just a function declared in the scope of a type (class, struct, protocol, enum).

tableView is the name of the method?

Yes... in one sense. It's what is often called the "base name" of a function/method — the part before the open-parenthesis (. The full name of the method, which people use when trying to unambiguously refer to this method versus others, includes all the argument labels: tableView(_:cellForRowAt:). (Even a full name isn't unambiguous in Swift, though, because functions/methods can be overloaded on parameter/return types.)

Usually a function name is a verb phrase, describing the action performed by a function or characterizing the result, but there's a longstanding convention otherwise in delegate/datasource protocols. (And this method is from the UITableViewDataSource protocol.) In such protocols, the "base name" of the function to name the object that's delegating some action.

What is _tableView? Is this the name of a parameter? If so, why do we need the underscore when cellForRowAt does not have an underscore, assuming cellForRowAt is also a name?

It's not _tableView, it's _ tableView — note the space. The underscore generally means "ignore this" in Swift. In this case, the underscore takes the place of an argument label, meaning that the caller of this method doesn't write one for the first parameter:

let cell = tableView(myTableView, cellForRowAt: selectedIndexPath)
^ nothing here, just the value being passed as an argument

Is UITableView a parameter type?
Is IndexPath a parameter type?

Yes.

What is indexPath in cellForRowAt indexPath? Why are there 2 words?

cellForRowAt is an argument label. indexPath is the internal (to your implementation) name of the parameter.

Argument labels are used by whoever calls your function — e.g. a call site for this looks like:

let cell = tableView(myTableView, cellForRowAt: selectedIndexPath)

Parameter names are how you refer to that value within the function body:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
...
self.doSomethingWithCellData(indexPath)
...
}

UITableViewCell is the return type, right?

Right. If you don't include a return statement in your implementation of this method, or return anything that isn't a UITableViewCell, the compiler gets upset.

Swift: difference between function calling

When encapsulated in a class (or struct or enum), the first parameter name of a method is not included externally, while all following parameter names are included externally. The parameters which are not included externally, you don't have to give names for them when calling the method. But for externally included ones you have to.

Your method incrementBy(amount: Int, numberOfTimes : Int) is encapsulated in your class that's why the second parameter is automatically externally included. Which means you have to type numberOfTimes before providing value to parameter. That's why you must call it like:

counter.incrementBy(1, numberOfTimes : 3)

Your second method func sampleFunc(firstName : String, lastName : String) is not enclosed in your class. That's why you don't have to provide name for its parameters. Which is why you can call it like:

sampleFunc("Abel", "Rosnoski")

You can read more details here.

Edit: As User3441734 kindly pointed out (And I quote) "There is one exception. init with parameters always requires named parameter, if the external name is not specified as _ ". You can read more about Customizing initialization here.

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

What does _: mean in Swift?

It's a way of stating the name of the function. The function might be declared like this:

func recordResponse(s:String) {
// ...
}

Now, by default, the s is an internal parameter name only; the external parameter name is suppressed. So we need a notation that describes the function, recordResponse, as taking one parameter with no external name. That notation is recordResponse(_:). The colon follows each parameter name — here there is only one parameter, and has no external name, which is what the underscore indicates.

In the usage you are asking about, this notation is just that: a notation. It's a convention for giving the name of the function in a complete way, when humans talk to humans (as in a tutorial). But in Swift 2.2, this notation will become very important, because it will be part of the language — it's how you'll form a function reference. That is, it will be Swift's own name for the function.

In Swift, what does the ! symbol mean in a function signature?

This isn't quite a duplicate — there's some subtlety to implicitly unwrapped optionals in function signatures beyond their usage elsewhere.

You see implicitly unwrapped optionals in API imported from ObjC because that's the closest Swift approximation of an object that's expected to be there but which can be nil. It's a compromise for imported API — you can address these variables directly like in ObjC, and you can test them for nil using Swift optional syntax. (There's more about Apple's rationale for this in the Advanced Interoperability talk from WWDC14.) This pattern also applies to the IBAction declarations inserted by Interface Builder, since those methods are in effect getting called from ObjC code, too.

As you seem to have suspected, Swift wraps the possible nil in an optional when bridging from ObjC, but the ! in your function implementation's declaration unwraps the value so you can use it directly. (At your own risk.)

Since Swift 1.2 (Xcode 6.2 in Spring 2015), ObjC APIs can be annotated with nonnull and nullable, in which case the Swift interface to those APIs uses either a non-optional type or a fully optional type. (And since Swift 2.0 / Xcode 7.0, nearly all of Apple's APIs are audited to use nullability annotations, so their Swift signatures don't use much ! anymore.)

What's less well-known about this is that you're free to change the optionality of parameters when you implement your own Swift functions that get called by ObjC. If you want the compiler to enforce that sender in your action method can never be nil, you can take the ! off the parameter type. If you want the compiler to make sure you always test the parameter, change the ! to a ?.

What are the differences between functions and methods in Swift?

After a few hours of reading and experimenting, here are the things that I found out:-

Functions in Swift

Functions are self-contained chunks of code that perform a specific
task. You give a function a name that identifies what it does, and
this name is used to “call” the function to perform its task when
needed.

Resource: Official Apple Documentation on Functions in Swift

Function Parameter Names

However, these parameter names are only used within the body of the
function itself, and cannot be used when calling the function. These
kinds of parameter names are known as local parameter names, because
they are only available for use within the function’s body.

It means that by default, all the parameters for Function are local parameters.

But, sometimes we want to indicate the purpose of each parameter. So, we can actually define an external parameter name for each parameter. Example Code:

func someFunction(externalParameterName localParameterName: Int) {
// function body goes here, and can use localParameterName
// to refer to the argument value for that parameter
}

Another way to make the external parameter name is using hash symbol (#) to shorten the name.

func someFunction(#localParameterName: Int) {
// function body goes here, and can use localParameterName
// to refer to the argument value for that parameter
}

To call the above functions with external parameter, you may use

someFunction(localParameterName:10)

Methods in Swift

Methods are functions that are associated with a particular type.
Classes, structures, and enumerations can all define instance methods,
which encapsulate specific tasks and functionality for working with an
instance of a given type.

Resource: Official Apple Documentation on Methods in Swift

However, the default behavior of local names and external names is
different for functions and methods.

Specifically, 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.

Code below shows the differences for default and non-default parameters for method in Swift.

import Foundation
import UIKit

class ViewController2: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()

//Default methods calling
var dailyStatement = greet("Rick", day: "Tuesday")
println(dailyStatement)

//First parameter is also an external parameter
var dailyStatement2 = greet2(name:"John", day: "Sunday")
println(dailyStatement2)
}

//Default: First Parameter is the local parameter, the rest are external parameters
func greet (name: String, day: String) -> String {
return "Hello \(name), today is \(day)."
}

//Use Hash symbol to make the First parameter as external parameter
func greet2 (#name: String, day: String) -> String {
return "Hello \(name), today is \(day)."
}
}

I might miss some important details. Hope someone can provide a better answer.

Why does a function call require the parameter name in Swift?

Update for Swift 2.0: Now functions behave identically to methods, and for both, by default:

  • the first parameter has no external name; and
  • the other parameters have an external name identical to the internal name.

Other than that, the rules below still apply, except that the # shorthand syntax is now gone.


Here's a more general answer: functions behave differently when defined as true functions outside a class, and when defined as methods. Moreover, init methods have a special rule.


Functions

Suppose you define this:

func multiply1(f1: Double, f2: Double) -> Double {
return f1 * f2
}

Parameter names are here only local to the function, and cannot be used when calling the function:

multiply1(10.0, 10.0)

If you want to force using named parameters when calling the function, you can. Prefix each parameter declaration with its external name. Here, the external name of f1 is f1param, and for f2, we use the shorthand where we prefix it by # to indicate that the local name is to be used as the external name as well:

func multiply2(f1param f1: Double, #f2: Double) -> Double {
return f1 * f2
}

Then, named parameters must be used:

multiply2(f1param: 10.0, f2: 10.0)

Methods

Things are different for methods. By default, all but the first parameter are named, as you've discovered. Suppose we have this, and consider the multiply1 method:

class Calc {
func multiply1(f1: Double, f2: Double) -> Double {
return f1 * f2
}
func multiply2(f1param f1: Double, f2: Double) -> Double {
return f1 * f2
}
func multiply3(f1: Double, _ f2: Double) -> Double {
return f1 * f2
}
}

Then, you have to use the name of the second (and following, if any) parameters:

let calc = Calc()
calc.multiply1(1.0, f2: 10.0)

You can force to use a named param for the first argument by providing an external name for it, like for functions (or prefixing its local name with # if you want to use the same external name as its local name). Then, you have to use it:

calc.multiply2(f1param: 10.0, f2: 10.0)

Finally, you can declare an external name of _ for the other following arguments, indicating that you want to call your method without using named parameters, like this:

calc.multiply3(10.0, 10.0)

Interoperability note: If you prefix class Calc with the @objc annotation, then you can use it from Objective-C code, and it is equivalent to this declaration (look at parameter names):

@interface Calc
- (double)multiply1:(double)f1 f2:(double)f2;
- (double)multiply2WithF1param:(double)f1 f2:(double)f2;
- (double)multiply3:(double)f1 :(double)f2;
@end

Init Methods

The rule differs a bit for init methods, where all parameters have an external name by default. For instance, this works:

class Calc {
init(start: Int) {}
init(_ start: String) {}
}

let c1 = Calc(start: 6)
let c2 = Calc("6")

Here, you have to specify start: for the overload that accepts an Int, but you must omit it for the overload that accepts a String.

Interoperability note: this class would get exported to Objective-C like this:

@interface Calc
- (instancetype)initWithStart:(NSInteger)start __attribute__((objc_designated_initializer));
- (instancetype)init:(NSString *)start __attribute__((objc_designated_initializer));
@end

Closures

Assume you define a closure type like this:

typealias FancyFunction = (f1: Double, f2: Double) -> Double

The parameter names will behave very similar to those in a method. You will have to provide the names to the parameters when calling the closure unless you explicitly set the external name to _.

For example, executing the closure:

fund doSomethingInteresting(withFunction: FancyFunction) {
withFunction(f1: 1.0, f2: 3.0)
}

As a rule of thumb: even if you dislike them, you should probably try to keep using named parameters at least whenever two parameters have the same type, in order to disambiguate them. I'd also argue that it's good to also name at least all Int and Boolean parameters.

What is _: in Swift telling me?

The _ is used to define that the parameter is not named

If you have multiple _ it states that you do not need to name the parameters in your function call

func myFunc(name:String, _ age:String){
}

myFunc(“Milo", "I'm a really old wizard")

If you do not use the underscore you would use

myFunc(“Milo”, age: "I'm a really old wizard")

The _ is not necessary for function calls. It is just used to indicate that something does not need to have a name.

In regards to how you would refer to your function, You would not have to pass any name for the function call.

But since you also don’t define a parameter type this seems to me like an invalid example (it at least doesn’t work in Xcode 7 with Swift 2.0)

Edit:

Since Swift 3.0

myFunc(name: “Milo”, age: "I'm a really old wizard")

Should be used



Related Topics



Leave a reply



Submit