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 10A 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:
- _“What is the original price?”
- _“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.99is the argument for the parameteroriginalPrice— it answers “What is the original price?”20.0is the argument for the parameterdiscountPercentage— 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.992The 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
| Concept | In Swift | Key Idea |
|---|---|---|
| Declaration | func name(param: Type) -> ReturnType { } | Defines a function; no code runs |
| Invocation | name(param: value) | Runs the function with specific values |
| Parameter | Named placeholder in the declaration | The question the function asks |
| Argument | Specific value passed at the call site | The answer (argument = answer) |
| Return value | -> Type and return value | Output sent back to the caller |
| Void function | No -> annotation | Performs work but produces no output |
