Skip to main content

Working with Functions

1. Defining Functions

Aspect Description Example
Function Declaration Basic syntax for defining a function
func greet(name: String) -> String {
    return "Hello, \(name)!"
}
Function Parameters Parameters can have labels and default values
func greet(greeting: String = "Hello", name: String) -> String {
    return "\(greeting), \(name)!"
}
Variadic Parameters Accept a variable number of arguments
func sum(numbers: Int...) -> Int {
    return numbers.reduce(0, +)
}
In-Out Parameters Modify a value passed into the function
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}
Function Types Functions can be assigned to variables or passed as arguments let functionVariable: (Int, Int) -> Int = addTwoInts

Example: Function with Multiple Return Values

func calculateStats(numbers: [Int]) -> (min: Int, max: Int, sum: Int) {
    let min = numbers.min() ?? 0
    let max = numbers.max() ?? 0
    let sum = numbers.reduce(0, +)
    return (min, max, sum)
}

2. Using Function Parameters

Parameter Type Description Example
Input Parameter Value passed into the function func greet(name: String) {<br> print("Hello, \(name)!")<br>}
Default Parameter Parameter with a default value if not provided func greet(name: String = "World") {<br> print("Hello, \(name)!")<br>}
External Parameter Name Used when calling the function, distinct from internal name func greet(greeting: String, to name: String) {<br> print("\(greeting), \(name)!")<br>}
Internal Parameter Name Used inside the function body func calculate(distance: Double, time: Double) -> Double {<br> return distance / time<br>}
Variadic Parameter Accepts zero or more values of the same type func sum(numbers: Int...) -> Int {<br> return numbers.reduce(0, +)<br>}

Example: Function with Multiple Parameter Types

func processUser(id: Int, name: String = "Anonymous", greeting: String = "Welcome") {<br>    print("\(greeting), \(name)! ID: \(id)")<br>}

Example: Variadic Parameter Usage

let total = sum(numbers: 1, 2, 3, 4, 5)<br>print(total) // Output: 15

3. Specifying Return Types (->)

Function Return Type Description
func greet() -> String String Returns a greeting message
func calculateSum(a: Int, b: Int) -> Int Int Calculates and returns the sum of two integers
func isEven(_ number: Int) -> Bool Bool Returns true if the number is even, false otherwise
func getArray() -> [String] [String] Returns an array of strings
func processValue(value: Double) -> Double? Double? Returns an optional double value after processing

Example: Function with Return Type

func calculateArea(length: Double, width: Double) -> Double {
    return length * width
}

let area = calculateArea(length: 5.0, width: 3.0)
print(area) // Output: 15.0

Example: Function Returning Optional

func findElement(in array: [Int], target: Int) -> Int? {
    guard let index = array.firstIndex(of: target) else {
        return nil
    }
    return array[index]
}

let numbers = [1, 2, 3, 4, 5]
let found = findElement(in: numbers, target: 3)
print(found ?? "Not found") // Output: 3

4. Using Default Parameter Values

Parameter Default Value Description
functionName(parameter: Type = defaultValue) defaultValue Defines a parameter with a default value that is used if the argument is not provided

Example: Function with Default Parameter

func greet(name: String, greeting: String = "Hello") -> String {
    return "\(greeting), \(name)!\quot;
}

print(greet(name: "Alice")) // Output: Hello, Alice!
print(greet(name: "Bob", greeting: "Hi")) // Output: Hi, Bob!
Note: Default parameter values must come after all non-default parameters in the function signature.

5. Using Variadic Parameters (...)

Variadic parameters allow a function to accept a variable number of arguments of the same type. The parameter is declared with an ellipsis (...) after its type.

Parameter Description Usage
func functionName(_ parameter: Type...) Declares a variadic parameter func sum(_ numbers: Int...) -> Int { ... }

Example: Using Variadic Parameters

func printNames(_ names: String...) {
    for name in names {
        print(name)
    }
}

printNames("Alice", "Bob", "Charlie")
// Output:
// Alice
// Bob
// Charlie
Note: Variadic parameters must be the last parameter in a function's parameter list.

Example: Variadic with Other Parameters

func greet(greeting: String, names: String...) {
    for name in names {
        print("\(greeting), \(name)!")
    }
}

greet(greeting: "Hello", names: "John", "Jane", "Jim")
// Output:
// Hello, John!
// Hello, Jane!
// Hello, Jim!

6. Using Inout Parameters

Parameter Description Usage
inout Allows a function to modify the value of a variable passed as an argument func modifyValue(inout value: Int) { value += 10 }

Example: Modifying a Variable with Inout

func incrementValue(inout value: Int) {
    value += 1
}

var number = 5
incrementValue(inout: &number)
print(number) // Prints: 6
Note: The & prefix is required when passing a variable to an inout parameter.
Warning: inout parameters cannot be used with constants or immutable values.

7. Defining Function Types

Function Type Description Example
(() -> Void) Function that takes no parameters and returns nothing let noParamNoReturn: () -> Void = { }
((Int, Int) -> Int) Function that takes two integers and returns an integer let add: (Int, Int) -> Int = { x, y in x + y }
((String) -> String) Function that takes a string and returns a string let upper: (String) -> String = { s in s.uppercased() }
((Int) -> (Int) -> Int) Function that returns another function let multiply: (Int) -> (Int) -> Int = { x in { y in x * y } }

Example: Function Type Alias

typealias MathOperation = (Int, Int) -> Int
let add: MathOperation = { x, y in x + y }
let multiply: MathOperation = { x, y in x * y }

Example: Function Type as Parameter

func applyOperation(_ operation: (Int, Int) -> Int, a: Int, b: Int) -> Int {
    return operation(a, b)
}
let result = applyOperation(add, a: 5, b: 3) // 8

8. Using Functions as Parameters

In Swift, functions can be passed as parameters to other functions. This allows for higher-order functions and enables powerful functional programming patterns.

Function Type Description Example
((Int, Int) -> Int) Function that takes two integers and returns an integer (a, b) -> a + b
((String) -> Void) Function that takes a string and returns nothing { print($0) }

Example: Passing a Function as a Parameter

func applyOperation(_ a: Int, _ b: Int, operation: (Int, Int) -> Int) -> Int {
    return operation(a, b)
}

let result = applyOperation(5, 3) { x, y in
    return x * y
}
print(result) // Output: 15

Example: Using Function Parameters in a Higher-Order Function

func processArray(_ numbers: [Int], operation: (Int) -> Int) -> [Int] {
    return numbers.map(operation)
}

let numbers = [1, 2, 3, 4]
let doubled = processArray(numbers) { num in
    return num * 2
}
print(doubled) // Output: [2, 4, 6, 8]

9. Using Functions as Return Types

In Swift, functions can be used as return types. This allows you to return a function from another function, which can then be called later.

Feature Description Example
Function as Return Type A function that returns another function.
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementer() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}

Example: Using Functions as Return Types

func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementer() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}

let incrementByTen = makeIncrementer(forIncrement: 10)
print(incrementByTen()) // Prints "10"
print(incrementByTen()) // Prints "20"

10. Creating Nested Functions

Nested functions are functions defined inside other functions in Swift. They can access variables and parameters from their enclosing function's scope.

Feature Description Example
Definition Functions defined inside another function
func outerFunction() {
    func innerFunction() {
        print("Inner function")
    }
    innerFunction()
}
Access to Outer Scope Can access variables and parameters from outer function
func greet(name: String) {
    func greeting() {
        print("Hello, \(name)")
    }
    greeting()
}
Return Nested Functions Can return nested functions as values
func makeIncrementer(amount: Int) -> (Int) -> Int {
    func incrementer(value: Int) -> Int {
        return value + amount
    }
    return incrementer
}

Example: Using Nested Functions for Encapsulation

func calculateTotal(items: [Double]) -> Double {
    func applyTax(amount: Double) -> Double {
        return amount * 1.08
    }
    
    func applyDiscount(amount: Double) -> Double {
        return amount * 0.9
    }
    
    let subtotal = items.reduce(0, +)
    let taxApplied = applyTax(amount: subtotal)
    return applyDiscount(amount: taxApplied)
}

let prices = [10.0, 20.0, 30.0]
let total = calculateTotal(items: prices)
print(total) // 58.32

Was this article helpful?