Swift Memory Exclusivity
Exclusivity of access means one piece of storage has only one modifying access at a time. The compiler enforces this rule for inout arguments and for methods that mutate a value.
One inout argument at a time
The addTen function takes one inout parameter. Each call finishes before the next call starts, so the two calls modify the score one after another.
func addTen(_ number: inout Int) {
number += 10
}
var score = 5
addTen(&score)
print(score)
addTen(&score)
print(score)A value argument beside an inout argument
The addValue function reads its first argument as a value and modifies its second argument through an inout parameter. Passing the same variable in both places compiles, and the balance doubles.
func addValue(_ amount: Int, to total: inout Int) {
total += amount
}
var balance = 20
addValue(balance, to: &balance)
print(balance)A method mutating its own storage
The increase method is marked mutating, so it can change the value stored in the Counter instance. Each call runs on its own and adds its amount to the stored value.
struct Counter {
var value: Int
mutating func increase(by amount: Int) {
value += amount
}
}
var counter = Counter(value: 3)
counter.increase(by: 4)
print(counter.value)
counter.increase(by: 1)
print(counter.value)The same variable in two inout parameters
The swapValues function takes two inout parameters, and the call passes the same variable to both of them. The compiler rejects the call, and the stated output is the first error line from that compile.
func swapValues(_ first: inout Int, _ second: inout Int) {
let held = first
first = second
second = held
}
var number = 10
swapValues(&number, &number)
print(number)Example
struct Counter {
var value: Int
mutating func increase(by amount: Int) {
value += amount
}
}
func doubleValue(_ number: inout Int) {
number += number
}
var counter = Counter(value: 3)
counter.increase(by: 4)
print(counter.value)
var score = 6
doubleValue(&score)
print(score)
doubleValue(&score)
print(score)Key points
- Passing a variable as an inout argument starts a modifying access to that variable.
- One variable can be passed to one inout parameter in a single call.
- The same variable cannot be passed to two inout parameters of one call, because the two accesses would overlap.
- A value argument beside an inout argument for the same variable is a reading access, and that shape compiles.
- A mutating method modifies the storage of its own value for the duration of the call.
- Separate calls made one after another do not overlap, so each call can modify the same variable in turn.
In this example, a mutating method raises a Counter from 3 to 7 by modifying its own storage. A separate inout function then doubles a score from 6 to 12 and again to 24. Each modifying access finishes before the next one starts.
Note
Copying a value into a separate variable gives the copy its own storage, so the copy can be modified on its own.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
Why does the compiler reject one call that passes the same variable to two inout parameters?