Swift Parameters and Return Values Explained with Examples

Swift functions become much more useful when they can accept input and send results back. This article explains how parameters and return values work in Swift, how argument labels affect function calls, when to use default values or inout, and how to avoid the most common mistakes beginners make.

Quick answer: In Swift, parameters let a function receive values from the caller, and return values let the function send a result back. You define parameter names and types inside the function declaration, then optionally declare a return type after ->.

Difficulty: Beginner

Helpful to know first: basic Swift syntax, variables and constants, and simple types like String, Int, and Bool.

1. What Is Parameters & Return Values?

A Swift function can take input values and produce an output value. The input values are called parameters, and the output value is called the return value.

For example, a function that adds two numbers needs two parameters. A function that checks whether a number is even might return a Bool. A function that prints a greeting may not return anything at all.

In Swift, this topic is often confused with argument labels and parameter names. They are closely related but not identical. A parameter name is used inside the function body, while an argument label is used when calling the function. You will see that distinction throughout this article.

2. Why Parameters & Return Values Matters

Without parameters, functions would be limited to hard-coded values. Without return values, functions could do work but would have no clean way to hand back a result.

Parameters and return values matter because they help you write code that is:

You should use parameters whenever a function needs information from outside. You should use return values whenever the caller needs a result back. If a function only performs a side effect, such as printing to the console, a return value may not be needed.

3. Basic Syntax or Core Idea

Declaring a function with parameters

This example shows the basic structure of a function that receives two values.

func add(a: Int, b: Int) {
    print(a + b)
}

Here, a and b are parameters. Both are of type Int. This function does not return a value; it only prints one.

Declaring a function with a return value

To return a result, add -> followed by the return type.

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

This function returns an Int instead of printing directly. That makes the function more flexible because the caller can store, print, or further process the result.

Calling the function

When you call the function, you pass arguments that match the parameters.

let total = add(a: 4, b: 6)
print(total)

The values 4 and 6 are arguments. They are passed into the parameters a and b.

4. Step-by-Step Examples

Example 1: A function with one parameter and no return value

This is the simplest useful pattern: give the function one input and let it perform an action.

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

greet(name: "Mina")

The function receives a String and uses it in the greeting. Because it does not return anything, its purpose is just the side effect of printing.

Example 2: A function with one parameter and one return value

Here the function computes something and returns the result.

func square(number: Int) -> Int {
    return number * number
}

let result = square(number: 5)
print(result)

The caller decides what to do with the returned value. That is usually better than printing inside the function.

Example 3: External argument label and internal parameter name

Swift lets you use one name when calling the function and another inside the function body. This can improve readability.

func multiply(first number: Int, by factor: Int) -> Int {
    return number * factor
}

let product = multiply(first: 3, by: 4)
print(product)

Inside the function, the names are number and factor. At the call site, the labels are first and by.

Example 4: Omitting the argument label with an underscore

Sometimes a label would make the call awkward. In that case, use _.

func isEven(_ value: Int) -> Bool {
    return value % 2 == 0
}

let check = isEven(8)
print(check)

The underscore removes the external argument label, so the call becomes shorter.

Example 5: Default parameter values

Default values let a caller skip some arguments when the default behavior is acceptable.

func welcome(name: String, punctuation: String = "!") -> String {
    return "Welcome, \(name)\(punctuation)"
}

print(welcome(name: "Ava"))
print(welcome(name: "Ava", punctuation: "!!!"))

The first call uses the default value. The second call overrides it.

Example 6: Returning multiple values with a tuple

Swift functions can return more than one value by returning a tuple.

func minMax(numbers: [Int]) -> (min: Int, max: Int) {
    var currentMin = numbers[0]
    var currentMax = numbers[0]

    for number in numbers {
        if number < currentMin {
            currentMin = number
        }
        if number > currentMax {
            currentMax = number
        }
    }

    return (min: currentMin, max: currentMax)
}

let range = minMax(numbers: [3, 9, 1, 7])
print(range.min)
print(range.max)

This is a useful pattern when two or more returned values naturally belong together.

5. Practical Use Cases

6. Common Mistakes

Mistake 1: Using the wrong argument label

Swift checks function calls carefully, including the labels used at the call site. If the labels do not match the declaration, the call fails.

Problem: This call uses a label that the function does not expect, which can produce an error such as extraneous argument label or missing argument for parameter.

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

greet(person: "Lina")

Fix: Call the function with the exact argument label defined in the function declaration.

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

greet(name: "Lina")

The corrected version works because the argument label now matches the function signature.

Mistake 2: Forgetting to return a value from a function that declares a return type

If a function says it returns a type, every valid path through that function must provide a value of that type.

Problem: This function declares that it returns an Int but does not return anything, which causes a compile-time error.

func double(number: Int) -> Int {
    number * 2
}

Fix: Use the return keyword to send a value back from the function.

func double(number: Int) -> Int {
    return number * 2
}

The corrected version works because the function now returns the Int it promised.

Mistake 3: Expecting a parameter to change the original value without using inout

By default, Swift passes function arguments by value. Changing a parameter inside the function does not change the original variable outside the function.

Problem: This code changes only the local copy of the parameter, so the original value remains unchanged after the function call.

func increase(value: Int) {
    var value = value
    value += 1
}

var score = 10
increase(value: score)
print(score)

Fix: Use an inout parameter when the function should modify the caller's variable, and pass the argument with &.

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

var score = 10
increase(value: &score)
print(score)

The corrected version works because inout allows the function to modify the caller's variable directly.

Mistake 4: Passing a constant to an inout parameter

An inout parameter requires a mutable variable because the function may change it.

Problem: This code passes a constant to an inout parameter, which causes a compile-time error because constants cannot be modified.

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

let score = 10
increase(value: &score)

Fix: Pass a var value instead of a let constant.

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

var score = 10
increase(value: &score)

The corrected version works because mutable variables can be safely passed to inout parameters.

7. Best Practices

Use clear argument labels for readable calls

Good labels make function calls easier to understand without reading the implementation.

// Less clear
func move(x: Int, y: Int) {
    print("Move to \(x), \(y)")
}

// Preferred
func move(toX x: Int, y: Int) {
    print("Move to \(x), \(y)")
}

Readable calls reduce mistakes and make APIs easier to use correctly.

Return values instead of printing inside utility functions

A function that returns data is usually more reusable than one that prints directly.

// Less flexible
func area(width: Int, height: Int) {
    print(width * height)
}

// Preferred
func area(width: Int, height: Int) -> Int {
    return width * height
}

The returned value can be stored, tested, compared, or displayed later.

Use default parameters to simplify common calls

If most callers use the same value, a default parameter reduces repetition while still allowing overrides.

func repeatText(_ text: String, times: Int = 2) -> String {
    var result = ""

    for _ in 1...times {
        result += text
    }

    return result
}

This keeps the simple case simple while preserving flexibility.

Use tuples only when the returned values naturally belong together

Tuples are convenient, but they are best for small grouped results. If the data becomes more complex, a custom type may be clearer.

func dimensions() -> (width: Int, height: Int) {
    return (width: 1920, height: 1080)
}

This pattern is clean for a small result pair such as width and height.

8. Limitations and Edge Cases

9. Practical Mini Project

This mini project builds a small score-reporting function set. It uses parameters, a tuple return value, and a default parameter so you can see several ideas working together.

func calculateStats(scores: [Int], bonus: Int = 0) -> (total: Int, average: Double, passed: Bool) {
    var sum = 0

    for score in scores {
        sum += score
    }

    sum += bonus

    let average = Double(sum) / Double(scores.count)
    let passed = average >= 60

    return (total: sum, average: average, passed: passed)
}

let report = calculateStats(scores: [70, 85, 90], bonus: 5)

print("Total: \(report.total)")
print("Average: \(report.average)")
print("Passed: \(report.passed)")

This example accepts an array of scores and an optional bonus. It returns three related values as a tuple: the total, average, and pass status. The result is easy to use because each returned value has a descriptive tuple label.

In production code, you would usually add protection for an empty scores array to avoid dividing by zero.

10. Key Points

11. Practice Exercise

Try building a function that calculates a discounted price.

Expected output: two discounted prices printed to the console.

Hint: Convert the percentage into a decimal value before subtracting it from the original price.

func discountedPrice(price: Double, discountPercent: Double = 10) -> Double {
    let discountAmount = price * (discountPercent / 100)
    return price - discountAmount
}

let salePrice1 = discountedPrice(price: 80.0)
let salePrice2 = discountedPrice(price: 80.0, discountPercent: 25.0)

print(salePrice1)
print(salePrice2)

12. Final Summary

Swift parameters and return values are the foundation of useful functions. Parameters allow you to pass information into a function, and return values allow the function to send results back in a clean, predictable way. Once you understand that flow of input and output, your functions become much easier to reuse and combine.

You also saw several important Swift-specific details: argument labels, omitted labels with _, default parameter values, tuple returns, and inout parameters. These features make Swift functions expressive, but they also introduce some common mistakes, especially with labels and missing return statements.

A strong next step is to learn how Swift function types, closures, and parameter passing patterns work. Those topics build directly on the syntax and ideas covered here.