A function is a named, reusable block of code that accepts input, performs some work, and optionally produces output. Functions let you break a program into well-named, testable pieces and avoid repeating the same logic in multiple places.

Declaring vs. Calling a Function

These two ideas are distinct and worth keeping separate in your mind.

Declaring a function means defining it — writing out its name, the inputs it expects, the work it does, and the output it produces. A declaration does not execute any code. It only describes what the function will do when used.

Calling a function (also called invoking it) means running it — passing in specific values and triggering the code inside the body to execute.

// DECLARATION — defines the function; no code runs here
func double(number: Int) -> Int {
    return number * 2
}
 
// INVOCATION — runs the function with a specific value
let result = double(number: 5)   // result is 10

A useful analogy: a function declaration is like a recipe written in a cookbook. No food is produced when the recipe is written down. Food only appears when someone follows the recipe — that is the equivalent of calling the function.

Parameters

A parameter is a named placeholder defined in the function’s declaration. It represents a value the function will need in order to do its work, but the specific value is not known until the function is called.

A helpful way to think about parameters: a parameter is essentially a question that the function asks.

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

Here, name is a parameter. The function is asking: “What name should I use for the greeting?” The parameter defines what kind of information the function needs — a String — and gives it a label to use inside the body.

A function can have multiple parameters, one for each piece of information it needs:

func discountedPrice(originalPrice: Double, discountPercentage: Double) -> Double {
    return originalPrice * (1.0 - discountPercentage / 100.0)
}

This function asks two questions:

  1. _“What is the original price?”
  2. _“What is the discount percentage?”

Arguments

When you call a function, the specific values you pass in are called arguments.

A memory tip: both argument and answer start with the letter a. An argument is the answer to the question a parameter asks.

let salePrice = discountedPrice(originalPrice: 49.99, discountPercentage: 20.0)

Here:

  • 49.99 is the argument for the parameter originalPrice — it answers “What is the original price?”
  • 20.0 is the argument for the parameter discountPercentage — it answers “What is the discount percentage?”

The parameter exists in the declaration. The argument exists at the call site. Same function, two very different roles.

Return Values

A function sends output back to the caller using a return value. The return type is written after the -> arrow in the function signature, and the return keyword delivers the value:

func discountedPrice(originalPrice: Double, discountPercentage: Double) -> Double {
    return originalPrice * (1.0 - discountPercentage / 100.0)
}
 
let salePrice = discountedPrice(originalPrice: 49.99, discountPercentage: 20.0)
print(salePrice)   // 39.992

The return type tells both Swift and the reader what kind of value to expect back. Once the return statement executes, the function ends and the value is handed back to wherever the call was made.

If a function performs work but does not need to produce output, the return type is omitted entirely. The return type is implicitly Void:

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

No -> annotation, no return statement needed.

An MVVM Example

The following small SwiftUI app brings these ideas together. A store displays a list of products on sale, and a function in the view model calculates the discounted price of each item.

TIP

Optionally, download this app and try it out.

Model

Product.swift

import Foundation
 
struct Product: Identifiable {
 
    // MARK: Stored properties
    let id = UUID()
    let name: String
    let price: Double
 
}

View Model

StoreViewModel.swift

import Foundation
import Observation
 
@Observable
class StoreViewModel {
 
    // MARK: Stored properties
    var discountPercentage: Double = 20.0
    
    var products: [Product] = [
        Product(name: "Wireless Headphones", price: 129.99),
        Product(name: "USB-C Hub",           price:  59.99),
        Product(name: "Mechanical Keyboard", price: 149.99),
        Product(name: "Webcam",              price:  89.99),
        Product(name: "Desk Lamp",           price:  44.99),
    ]
 
    // MARK: Functions
    func discountedPrice(originalPrice: Double, discountPercentage: Double) -> Double {
        return originalPrice * (1.0 - discountPercentage / 100.0)
    }
 
}

The function discountedPrice is declared here. It asks two questions via its parameters — “What is the original price?” and “What is the discount percentage?” — and promises to return a Double. No calculation takes place at this point. The function body only runs when the function is called.

View

ContentView.swift

import SwiftUI
 
struct ContentView: View {
 
    // MARK: Stored properties
    @State var viewModel = StoreViewModel()
 
    // MARK: Computed properties
    var body: some View {
        NavigationStack {
            List {
                ForEach(viewModel.products) { product in
 
                    let salePrice = viewModel.discountedPrice(
                        originalPrice: product.price,
                        discountPercentage: viewModel.discountPercentage
                    )
 
                    HStack {
                        VStack(alignment: .leading) {
                            Text(product.name)
                                .font(.headline)
                            Text(String(format: "$%.2f", product.price))
                                .font(.subheadline)
                                .foregroundStyle(.secondary)
                                .strikethrough()
                        }
                        Spacer()
                        Text(String(format: "$%.2f", salePrice))
                            .font(.headline)
                            .foregroundStyle(.green)
                    }
 
                }
            }
            .navigationTitle("Sale — \(Int(viewModel.discountPercentage))% Off")
        }
    }
 
}
 
#Preview {
    ContentView()
}

The let salePrice = viewModel.discountedPrice(...) line inside ForEach is the function call. This is where the function actually runs. The arguments — product.price and viewModel.discountPercentage — are the answers to the questions the parameters ask.

Because product is a different value on each pass through ForEach, the argument passed for originalPrice changes each time. The same declared function is called five times with five different sets of arguments, producing five different return values. This is one of the core reasons functions are useful: write the logic once, reuse it with any input.

Summary

ConceptIn SwiftKey Idea
Declarationfunc name(param: Type) -> ReturnType { }Defines a function; no code runs
Invocationname(param: value)Runs the function with specific values
ParameterNamed placeholder in the declarationThe question the function asks
ArgumentSpecific value passed at the call siteThe answer (argument = answer)
Return value-> Type and return valueOutput sent back to the caller
Void functionNo -> annotationPerforms work but produces no output