Swift Programming – Functions

In this tutorial you’ll learn about functions in Swift. To follow along, it is recommended to have a Mac and the Xcode IDE installed on it. This tutorial makes use of the Xcode playground for compilation of the Swift codes. If you do not have a Mac, you may try using the open-source code editors which support different operating systems such as AtomSublimeText or VSCode.

Functions

A function is written to perform a specific task. Instead of writing the same piece of codes multiple times, you use a function to contain it and then you can call the function countless times you want. For example, let’s say you want to perform sum of an array of integers, you can write a function with codes specific to that. You define a function with the keyword func, followed by the name of the function calculateSum taking one parameter, an array of integers, which returns an Int (known as a return type) as the computational value.

func calculateSum(numbers: [Int])  -> Int {
    var sum = 0

    for number in numbers {
        sum+=number
    }

    return sum
}

print(calculateSum(numbers: [2, 4, 6, 8, 10]))

A function can take one or more parameters or no parameters. It can return a value as a result or no value.

Let’s see some examples of functions with no parameter and no return type.

// function with no parameter which returns a String

func getDefaultText() -> String {
    return "Hello World!"
}

print(getDefaultText())

// function with one parameter a String which has no return type

func getText(name: String) {
    print("Hello \(name)!")
}

getText(name: "Zakhia")

You can return a tuple as a return type of a function. Let’s say you want to calculate the sum and average of an array of Double type.

func getSumAndAverage(numbers: [Double]) -> (sum: Double, average: Double) {
    var sum = 0.0

    for number in numbers {
        sum+=number
    }
    
    let average = sum / Double(numbers.count)
    
    return (sum, average)
}

let numbers = [3.0, 6.0, 9.0, 12.0, 15.0]
let sumAndAverage = getSumAndAverage(numbers: numbers)
print("Sum of \(numbers) is \(sumAndAverage.sum) and average is \(sumAndAverage.average)")

Implicit Return

If a function contains only one line of code, then you can use an implicit return, which means that we can omit the keyword return. Recall our previous example getDefaultText():

func getDefaultText2() -> String {
    "Hello World!"
}

Function Argument Labels and Parameter Names

In Swift, a function is known to have an argument label and a parameter name. If no explicit argument label is provided in a function, then the parameter name is considered to be both the argument label and the parameter name. Basically, if you provide an argument label and a parameter name, the argument label is used in the call of the function and the parameter name is used inside the function.

// function with parameter name & argument label (year)
func getAge(year: Int) -> Int {
    let currentYear = Calendar.current.component(.year, from: Date())
    return currentYear - year
}

// function with explicit argument label (for) and parameter name (year)
func getAge(for year: Int) -> Int {
    getAge(year: year)
}

var year = 1993
var age = getAge(year: year)

print("If year born is \(year) then your age must be \(age) this year")

year = 1964
age = getAge(for: year)

print("If year born is \(year) then your age must be \(age) this year")

Omitting Argument Labels

Recall our previous function getAge(year:), we can omit the argument label by placing an underscore (_) just before the parameter name.

// function omitted the argument label
func getAge(_ year: Int) -> Int {
    getAge(for: year)
}

year = 1983
age = getAge(year)

print("If year born is \(year) then your age must be \(age) this year")

Default Parameter Values

You can provide a default value to the parameter so that you can omit the parameter name in the function call.

func greetUser(name: String = "there") -> String {
    "Hi \(name)!"
}

print(greetUser())
print(greetUser(name: "Zakhia"))

Variadic Parameters

You can use a variadic parameter as an alternative way of passing an array as a parameter in a function. Recall our function calculateSum(numbers:), instead of making the parameter type an array of integers, we can use a variadic parameter type like this Int….

func calculateSum(numbers: Int...) -> Int {
    calculateSum(numbers: numbers)
}

print(calculateSum(numbers: 1, 2, 3, 4, 5, 6))

Notice that our previous function calculateSum(numbers:) considers the parameter numbers of our new function as an array. Also, see the difference of putting the numbers as parameter in the call of the newly created function. In our first example we put the numbers in between square brackets, whilst in this one, we omitted the square brackets.

In-Out Parameters

In Swift, all parameters in a function are constants by default, which means that we cannot modify the parameter inside the function. We can use an in-out parameter to be able to modify it inside the function. When calling a function with an in-out parameter we have to put an ampersand (&) before the variable we are passing as parameter in the function.

var output = calculateSum(numbers: 34, 45, 65, 70, 98, 100)

func getAverage(of value: inout Int, count: Int) {
    value = value / count
}

getAverage(of: &output, count: 6)
print(output)

Note that if you use a variadic parameter, for instance, to accept a series of numbers, you can’t know how much numbers are in there. However, with an array of numbers, you have the possibility of knowing that by doing something like numbers.count to get it.

Function Types

A function type is the combination of the parameter types and the return types of a function.

func getSum(_ x: Int, _ y: Int) -> Int {
    x + y
}

func getAverage(_ x: Int, _ y: Int) -> Int {
    (x + y) / 2
}

func displayWelcome() {
    print("Welcome")
}

var x = 25
var y = 80
let sum = getSum(x, y)
let average = getAverage(x, y)

print("Sum of \(x) and \(y) is \(sum) and its average is \(average)")
displayWelcome()

The function getSum(_:_:) and getAverage(_:_:), take two parameters, of type Int and return an Int. The function type of these two functions is therefore (Int, Int) -> Int.

The function displayWelcome() takes no parameters and have no return type. The function type of this function is therefore () -> Void.

Using Function Types

Swift provides function types to be used like any other types. For example, you can declare a variable with a specific function type and assign it to a function of that type.

x = 55
y = 115
var computationalFunction: (Int, Int) -> Int = getSum

print("computationFunction outputs \(computationalFunction(x, y))")

x = 77
y = 124
computationalFunction = getAverage

print("computationFunction outputs \(computationalFunction(x, y))")

Function Types as Parameter Types

You can use a function type as a parameter type of a function. Instead of writing the same printing codes of outputting the output multiple times like we did previously, we can create a new function that takes a function type and print the output.

func printOutputOfComputation(a: Int, b: Int, _ compute: (Int, Int) -> Int) {
    print("computationFunction outputs \(compute(a, b))")
}

printOutputOfComputation(a: 167, b: 230, computationalFunction)

Function Types as Return Types

You can return a function type in another function.

func computeAverage(numbers: [Int]) -> Int {
    calculateSum(numbers: numbers) / numbers.count
}

func compute(average: Bool) -> ([Int]) -> Int {
    average ? computeAverage : calculateSum
}

var integers = [12, 24, 36, 48, 54]
var computation = compute(average: false)

print("Sum of \(integers) is \(computation(integers))")
computation = compute(average: true)
print("Average of \(integers) is \(computation(integers))")

Nested Functions

Nested functions are functions written inside another function. All the functions we created so far, are known as global functions. The function computeAverage(numbers:) we previously created, can be moved inside the function compute(average:) as a nested function. A nested function is available within the enclosing function only.

func computeEnclosing(average: Bool) -> ([Int]) -> Int {
    func computeAverageNested(numbers: [Int]) -> Int {
        calculateSum(numbers: numbers) / numbers.count
    }
    
    return average ? computeAverageNested : calculateSum
}

integers = [5, 10, 15, 20, 25, 30, 35, 40]
computation = computeEnclosing(average: false)
print("Sum of \(integers) is \(computation(integers))")
computation = compute(average: true)
print("Average of \(integers) is \(computation(integers))")

Reference

https://docs.swift.org/swift-book/LanguageGuide/Functions.html