The function is a self-containing block of code for performing the specific task. The function is a thing, that we use every day. It’s like a building block for our code.

The general form of the Swift function is:

func funcName(paramName: ParamType, ...) -> ResultType {
  // Function body goes here...
}

Let’s see it closer using sample:

func doSomethingCool(foo: FooType, withBar bar: BarType, andBuz buz: BuzType) -> ResultType {
  // Function body goes here...
}
Notation Meaning
func Denotes that this is a function
doSomethingCool Name of the function
(foo: FooType, withBar bar: BarType, andBuz buz: BuzType) Parameters of the function
foo, bar, baz Parameters variable names
withBar, andBuz Parameters names
FooType, BarType, BazType Parameters types
ResultType The type of the returned result. Can be empty (Void)
{} Contains function body

Simplest function

The function can be simple. Let’s check the simplest one. It starts with func keyword and named printMessage, does not have arguments nor return value. It just performs code contained inside curly braces {...}

func printMessage() {
  print("Follow the white rabbit!")
}
printMessage()
// > Follow the white rabbit!

Parameters syntax

The function can accept parameters. For example, the following function accepts single String parameter with the name name.

func greet(name: String) {
  print("Hello, " + name)
}
greet(name: "Neo")
// > Hello, Neo!

The function can accept multiple parameters.

func punchAgentInFace(agentName: String, numTimes count: Int) {
  for _ in 0..<count {
    print("Punch agent \(agentName)")
  }
}
punchAgentInFace(agentName: "Smith", numTimes: 4)
// Prints 4 times
// > Punch agent Smith

If you want to omit parameter names replace them with _. That’s how previous function call will look like with second parameter name omitted:

func punchAgentInFace(agentName: String, _ count: Int) {
    for _ in 0..<count {
        print("Punch agent \(agentName)")
    }
}
punchAgentInFace(agentName: "Smith", 4)
// Prints 4 times
// > Punch agent Smith

Named parameters

If you want to make all parameters named, just type desired parameter name before the variable name. Just like in Objective-C. That’s how previous function will look like with named first parameter:

func punchAgentInFace(agent agentName: String, numTimes count: Int) {
  for _ in 0..<count {
    print("Punch agent \(agentName)")
  }
}
punchAgentInFace(agentName: "Smith", numTimes: 4)
// Prints 4 times
// > Punch agent Smith

Parameters with default values

The function can have default parameter values. If you skip parameter in a function call, it will take a default value. Otherwise, it will take passed value. Parameter name from the next code sample has default value "Neo".

func sayHello(_ name: String = "Neo") {
  print("Hello, \(name)!")
}
sayHello()
// > Hello, Neo!
sayHello("Morpheus")
// > Hello, Morpheus!

Variadic parameters

Variadic parameters are handy when parameters count is unknown. Variadic parameter is transformed to Array<ParamType>. To mark parameter as variadic use name: <Type>... syntax. See the following sample:

func inviteToParty(friends: String..., place: String) -> String {
    var invitation = "Dear friends! Let me invite you to the party! There will be "
    for friend in friends { // `friends` is [String] array
        invitation += "\(friend), "
    }
    return "\(invitation) and me. Place: \(place)"
}
inviteToParty(friends: "Trinity", "Morpheus", place: "Eastern part of Zion")
// > "Dear friends! Let me invite you to the party! There will be Trinity, Morpheus, and me. Place: Eastern part of Zion"

In-out parameters

As mentioned above, variable parameters can only be changed by the function itself. If you need the function to change some parameters from outside the function scope, you should use inout keyword. Keep in mind that inout parameters cannot have default values.

func swapAgents(_ agentA: inout String, _ agentB: inout String) {
    let temporaryA = agentA
    agentA = agentB
    agentB = temporaryA
}

var smith = "Smith"
var johnson = "Johnson"
swapAgents(&smith, &johnson)
print("Sminth is now \(smith), Johnson is now \(johnson)")
// > Sminth is now Johnson, Johnson is now Smith

Generic parameters

We can rewrite swapAgents(_:_:) function in a more general way. Using the following notation we tell that function accepts two parameters of any type, but the type of the parameter a is always the same as the parameter b type

func swap1<T>(_ a: inout T, _ b: inout T) {
    let temporaryA = a
    a = b
    b = temporaryA
}

var agentSmith = "Smith"
var agentJohnson = "Johnson"
swap1(&agentSmith, &agentJohnson)
print("Sminth is now \(smith), Johnson is now \(johnson)")
// > Sminth is now Johnson, Johnson is now Smith

var a = 1
var b = 2
swap1(&a, &b)
print("a is now \(a), b is now \(b)")
// > a is now 2, b is now 1

Return values syntax

Functions can return values. It is not required (all the functions above did not return any values). Basically, functions are small programs, which can return results of their work. As you can see, isThereASpoon(_:) function returns the single value of Bool type. In Swift, return value type is separated from function name with -> symbol.

func isThereASpoon(_ whoAsks: String) -> Bool {
  return whoAsks != "Neo"
}
print(isThereASpoon("Neo"))
// > false
print(isThereASpoon("Trinity"))
// > true

Multiple return values

Sometimes we need to receive multiple return values from a function. It is possible. Swift allows us to deal with it in an elegant way. The following code sample shows how to use and access multiple return values:

func distributeToShips(_ crew: [String]) -> (nebuchadnezzar: [String], osiris: [String]) {
    var nebuchadnezzarCrew = [String]()
    var osirisCrew = [String]()
    for i in 0..<crew.count {
        if i % 2 == 0 {
            nebuchadnezzarCrew.append(crew[i])
        } else {
            osirisCrew.append(crew[i])
        }
    }
    return (nebuchadnezzarCrew, osirisCrew)
}

let crew = distributeToShips(["Neo", "Morpheus", "Trinity", "Seraph", "Cipher", "Dozer", "Tank"])
print("Nebuchandezzar crew: \(crew.nebuchadnezzar); Osiris crew: \(crew.osiris)")
// > "Nebuchandezzar crew: ["Neo", "Trinity", "Cipher", "Tank"]; Osiris crew: ["Morpheus", "Seraph", "Dozer"]"

Optional tuple

If there is probability, that returning tuple will have no value, we should use an Optional tuple. The function above, rewritten with optional tuple, will look like this:

func distributeToShipsOptional(_ crew: [String] = []) -> (nebuchadnezzar: [String], osiris: [String])? {
    if crew.count > 0 {
        var nebuchadnezzarCrew = [String]()
        var osirisCrew = [String]()
        for i in 0..<crew.count {
            if i % 2 == 0 {
                nebuchadnezzarCrew.append(crew[i])
            } else {
                osirisCrew.append(crew[i])
            }
        }
        return (nebuchadnezzarCrew, osirisCrew)
    }
    return nil
}

if let crew = distributeToShipsOptional(["Neo", "Morpheus", "Trinity", "Seraph", "Cipher", "Dozer", "Tank"]) {
    print("Nebuchandezzar crew: \(crew.nebuchadnezzar); Osiris crew: \(crew.osiris)")
}
// > "Nebuchandezzar crew: ["Neo", "Trinity", "Cipher", "Tank"]; Osiris crew: ["Morpheus", "Seraph", "Dozer"]"

if let crew = distributeToShipsOptional() {
    print("Nebuchandezzar crew: \(crew.nebuchadnezzar); Osiris crew: \(crew.osiris)")
}
// >

Function type

You can pass any function as an argument or use it as a return value of any other function. In Swift, functions are first-class citizens. Function has a type. Function type general form is (argument types) -> return type. In the example below, both functions, plus(_: _:) and multiply(_: _:) has the same type: (Int, Int) -> Int. calculate(_: _: _:) function uses proper function depending on the operation passed as argument.

func plus(_ a: Int, _ b: Int) -> Int {
    return a + b
}

func multiply(_ a: Int, _ b: Int) -> Int {
    return a * b
}

// Function type is used as parameter type
func calculate(_ a: Int, b: Int, operation: (Int, Int) -> Int) -> Int {
    return operation(a, b)
}

print(calculate(3, b: 7, operation: plus))
// > 10
print(calculate(3, b: 7, operation: multiply))
// > 21

Function as return value

Function can also be used as return type of other function. mathFunction(_:) returns (Int, Int) -> Int function, which is used by calculate(_: _: _:) function from the previous example;

enum Operation {
    case plus
    case multiply
}

func mathFunction(_ operation: Operation) -> (Int, Int) -> Int {
    switch operation {
    case .plus:
        return plus
    case .multiply:
        return multiply
    }
}

print(calculate(10, b: 3, operation: mathFunction(.plus)))
// > 13
print(calculate(10, b: 3, operation: mathFunction(.multiply)))
// > 30

The type of the function can be named using typealias keyword. Let’s rewrite our math functions using typealas.

typealias OperationFunction = (Int, Int) -> Int

func plus1(_ a: Int, _ b: Int) -> Int {
    return a + b
}

func multiply1(_ a: Int, _ b: Int) -> Int {
    return a * b
}

// Function type is used as parameter type
func calculate1(_ a: Int, b: Int, operation: OperationFunction) -> Int {
    return operation(a, b)
}

print(calculate1(3, b: 7, operation: plus))
// > 10
print(calculate1(3, b: 7, operation: multiply))
// > 21

Nested functions

Nested functions are functions, used inside the other functions.

typealias Printer = () -> String

func whoWillWin(_ isOptimist: Bool) -> Printer {
    func neo() -> String { return "Neo" }
    func smith() -> String { return "Smith" }
    if isOptimist {
        return neo
    } else {
        return smith
    }
}

let iAmGood = true
print(whoWillWin(iAmGood)()) // Notice `functionName(param)()` syntax. Remember, `whoWillWin(_:)` returns function!
// > Neo

Conclusion

Functions in Swift are powerful and flexible. Different syntactical possibilities can be used to improve code informativity and reduce clatter.

Further reading