Understanding Swift: Pass by Value and Copy-on-Write
In this post, I want to talk about Swift's two great yet simple features. Pass by value and copy on write.
In Swift, understanding how data gets passed around is crucial for writing efficient code. Two key concepts come into play: pass by value and copy-on-write.
Pass by Value
Imagine you’re lending a book to a friend. In Swift’s world of value types (structs, enums, tuples), passing data is similar. When you assign a value type to a variable or pass it as a function argument, a copy of the data is created. This means any changes made within the function don’t affect the original value.
struct Book {
let title: String
let owner: String
}
var book1 = Book(title: "Swift", owner: "Apple")
var book2 = book1
func modifyOwner(book: Book) {
book.owner = "Medium" // This only modifies a copy of book
}
modifyOwner(book: book1)
print(book1.owner) // Output: Apple (Original value remains unchanged)
Copy-on-Write
Things get interesting with Swift’s collections (arrays, dictionaries, sets). While they’re technically value types, Swift utilizes a clever optimization technique called copy-on-write. Here’s the gist:
- When you assign a collection or pass it to a function, Swift initially avoids a full copy. Both the original and the new variable refer to the same underlying data.
- However, the moment you try to modify the collection (add, remove, or change elements), a copy is created only then. This new copy holds the modified data, while the original remains untouched.
This approach saves memory and processing power when the collection isn’t mutated.
Key points
- Value types are always passed by value (a copy is created).
- Swift’s collections use copy-on-write to optimize memory usage.
- Modifications to collections trigger a copy to be created.
Understanding these concepts helps you reason about how data behaves in your Swift programs. It allows you to write code that’s both efficient and predictable, avoiding unexpected side effects.