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.

  • A parameter gives a function data it needs to do its job.
  • A return value gives the caller the result of that work.
  • Parameters have types, just like variables and constants.
  • A function may have no parameters, one parameter, or many parameters.
  • A function may return nothing, a single value, or a tuple containing multiple values.

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:

  • Reusable: one function can work with many different inputs.
  • Readable: argument labels can make calls read like English.
  • Testable: functions that return values are easier to verify.
  • Modular: small functions can handle one task and return the result to other code.

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

Declaring a function with parameters

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

Swift
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.

Swift
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.

Swift
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.

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

greet(name: "Mina")
Output✓ Tested · Swift 6.4
Hello, 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.

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

let result = square(number: 5)
print(result)
Output✓ Tested · Swift 6.4
25

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.

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

let product = multiply(first: 3, by: 4)
print(product)
Output✓ Tested · Swift 6.4
12

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 _.

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

let check = isEven(8)
print(check)
Output✓ Tested · Swift 6.4
true

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.

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

print(welcome(name: "Ava"))
print(welcome(name: "Ava", punctuation: "!!!"))
Output✓ Tested · Swift 6.4
Welcome, Ava!
Welcome, Ava!!!

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.

Swift
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)
Output✓ Tested · Swift 6.4
1
9

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

5. Practical Use Cases

  • Passing a username, password, or email into a validation function.
  • Providing numbers to a math helper that returns a calculated result.
  • Sending a list into a function that returns summary information such as count, minimum, or average.
  • Creating formatting functions that receive text and return a display-ready string.
  • Using default parameters to reduce repeated boilerplate in common function calls.
  • Returning tuples when a function needs to provide closely related values, such as coordinates or a min/max pair.

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.

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

greet(person: "Lina")
Compiler output✓ Tested · Swift 6.4
error: incorrect argument label in call (have 'person:', expected 'name:')

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

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

greet(name: "Lina")
Output✓ Tested · Swift 6.4
Hello, 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. A body that is a single expression returns it implicitly (since Swift 5.1), but as soon as the body has more than one statement, you have to write return.

Problem: This function computes a value but never returns it, so the compiler reports “missing return in global function expected to return 'Int'”.

Swift
func double(number: Int) -> Int {
    let result = number * 2
}
Compiler output✓ Tested · Swift 6.4
error: missing return in global function expected to return 'Int'

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

Swift
func double(number: Int) -> Int {
    let result = number * 2
    return result
}

The corrected version works because the function now returns the Int it promised. A one-line body such as { number * 2 } would also work, because single-expression functions return implicitly.

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.

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

var score = 10
increase(value: score)
print(score)
Output✓ Tested · Swift 6.4
10

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

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

var score = 10
increase(value: &score)
print(score)
Output✓ Tested · Swift 6.4
11

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.

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

let score = 10
increase(value: &score)
Compiler output✓ Tested · Swift 6.4
error: cannot pass immutable value as inout argument: 'score' is a 'let' constant

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

Swift
func increase(value: inout 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.

Swift
// 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.

Swift
// 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.

Swift
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.

Swift
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

  • Function parameters are constants by default inside the function body. You cannot assign a new value to them unless you create a local variable or use inout.
  • A function with a declared return type must return a value on every possible path.
  • Returning a tuple is convenient, but very large tuples can make code harder to read and maintain.
  • inout should be used carefully because it makes data flow less obvious than returning a new value.
  • If an array might be empty, a tuple-returning function like minMax needs extra handling. Accessing numbers[0] on an empty array would crash.
  • Default parameter values can improve call sites, but too many defaults in one function can make behavior harder to understand.
  • Some "not working" function calls are really label mismatches. In Swift, labels are part of the function's public calling syntax.

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.

Swift
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)")
Output✓ Tested · Swift 6.4
Total: 250
Average: 83.33333333333333
Passed: true

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

  • Parameters give a function the input it needs to perform work.
  • Return values give the caller the result of that work.
  • Swift function calls use argument labels as part of the calling syntax.
  • You can omit an external label with _ when that makes the call clearer.
  • Default parameter values reduce repetition in common function calls.
  • Use inout only when a function must modify the caller's variable.
  • Tuples let a function return multiple related values in one result.
  • If a function declares a return type, every valid path must return a matching value.

11. Practice Exercise

Try building a function that calculates a discounted price.

  • Create a function named discountedPrice.
  • It should accept a required price parameter of type Double.
  • It should accept a discountPercent parameter of type Double with a default value of 10.
  • It should return the final price after applying the discount.
  • Call the function once with the default discount and once with a custom discount.

Expected output: two discounted prices printed to the console.

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

Show solution
Swift
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)
Output✓ Tested · Swift 6.4
72.0
60.0

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.