Swift
Programming
Collections
Immutable
Mutable

Immutable/Mutable Collections in Swift

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

In Swift, a collection is mutable or immutable based on whether you bind it with var or let. That sounds simple, but the full picture also involves value semantics, copy-on-write behavior, and the important difference between changing a collection itself and changing reference-type objects stored inside it.

let Means The Collection Value Cannot Change

If you declare an array, dictionary, or set with let, you cannot change its contents.

swift
let numbers = [1, 2, 3]
// numbers.append(4)  // error

The same rule applies to dictionaries and sets.

swift
let capitals = ["CA": "Ottawa", "FR": "Paris"]
// capitals["US"] = "Washington"  // error

In everyday Swift code, this is what immutable collection means: the collection value itself cannot be mutated.

var Means The Collection Value Can Change

If you bind the collection with var, you can add, remove, or replace elements.

swift
1var numbers = [1, 2, 3]
2numbers.append(4)
3numbers[0] = 99
4print(numbers)

For a dictionary:

swift
1var capitals = ["CA": "Ottawa", "FR": "Paris"]
2capitals["US"] = "Washington"
3capitals["FR"] = "Lyon"
4print(capitals)

That is the basic mutability rule most Swift code relies on.

Swift Collections Are Value Types

Swift arrays, dictionaries, and sets are value types. That means assigning one collection to another copies the value conceptually.

swift
1var a = [1, 2, 3]
2var b = a
3b.append(4)
4
5print(a)
6print(b)

a stays unchanged because b is a separate value.

This is a big difference from languages where collections are reference types by default.

Copy-On-Write Makes It Efficient

Even though collections are value types, Swift uses copy-on-write under the hood. That means the storage is usually shared until one copy is mutated.

So you get value semantics without paying for a full eager copy every time you assign a collection.

That is one reason Swift collections feel safe and convenient without being obviously inefficient.

Immutable Collection Does Not Freeze Reference-Type Elements

This is the subtle part many people miss.

If a let array contains class instances, you cannot replace or reorder the elements, but you may still be able to mutate the objects those elements reference.

swift
1final class User {
2    var name: String
3    init(name: String) {
4        self.name = name
5    }
6}
7
8let users = [User(name: "Ava")]
9users[0].name = "Noah"
10print(users[0].name)

The array is immutable, but the User instance is still mutable because User is a class.

So collection immutability and object immutability are not the same thing.

When To Prefer let

A good Swift rule is to default to let and switch to var only when mutation is actually required.

Benefits include:

  • clearer intent
  • fewer accidental changes
  • easier reasoning about state
  • safer concurrent reading patterns

This is one of the simplest ways to write more predictable Swift code.

A Practical Example

swift
1struct ShoppingList {
2    let owner: String
3    var items: [String]
4}
5
6var list = ShoppingList(owner: "Ava", items: ["Milk", "Bread"])
7list.items.append("Eggs")
8print(list)

Here the struct instance is mutable because it is bound to var, so its mutable collection property can change.

If the whole ShoppingList value were bound to let, then items could not be mutated through that binding.

Common Pitfalls

The most common mistake is assuming a let collection makes all contained objects deeply immutable. That is false when the elements are reference types.

Another mistake is forgetting that arrays, dictionaries, and sets are value types in Swift. Mutating a copy does not mutate the original collection value.

Developers also sometimes use var by default, which weakens intent and makes state changes harder to track.

Finally, do not confuse collection mutability with thread safety. Mutability rules help, but concurrent mutation still needs proper design and synchronization.

Summary

  • In Swift, let makes a collection immutable and var makes it mutable.
  • Arrays, dictionaries, and sets are value types.
  • Swift uses copy-on-write to make value semantics efficient.
  • A let collection can still contain mutable class instances.
  • Default to let unless your code truly needs to mutate the collection.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.