Skip to content
Theory · Arrays · lesson 7 of 8

Copies of arrays

Let's go back to the row of lockers. What happens when a program says var b = a? Picture a second row being built next to the first one, with the same items placed in it. From then on each row lives on its own: if you put something in the second row, the first one does not change.

Let's see what this looks like in code:

SWIFT
let a = [1, 2, 3]
var b = a
b.append(4)
print(a)  // [1, 2, 3]
print(b)  // [1, 2, 3, 4]

Let's go through the program line by line:

  1. let a = [1, 2, 3] builds the first row.
  2. var b = a builds a second row with the same elements. a loses nothing: assignment copies the elements, it does not take them away.
  3. b.append(4) adds a locker to the second row only.
  4. a prints as before, [1, 2, 3], and b prints with the new element.

Note that a is declared with let, and b with var. The copy has its own declaration, so b can change even though a is a constant.

An array is a value type

A type whose assignment and passing to a function create an independent copy is called a value type. Arrays in Swift are a value type, like Int and String. After var y = x, nobody expects a new value in y to change the number in x. Arrays work the same way.

Press "Next step" and compare a with b, and then with the arrays inside the function: only the array that append was applied to changes.

LiveEach array is a separate copystep 1 of 12 · frames: 1

The constant a is the first row, with three elements.

Watch a: its value does not change on any step

A function gets its own copy of an array too. In the example, withBonus receives a in the parameter scores and changes not that but the copy result, because a parameter is a constant. After the call, a is the same as before.

Interviewers often ask: what happens to the first array if you change the second? In Swift, nothing: an array is a value type. They ask because in many other languages, such as JavaScript and Python, both names would lead to one and the same array.

When Swift copies the elements

Copying a big array on every assignment would take a long time, so Swift does not do it right away. As long as neither array has been changed, they use the same elements. Right before the first change to one of them, Swift copies the elements for it. This technique is called copy-on-write.

Here the two-row picture is inaccurate. The second row is built not at the moment of var b = a, but when something in one of the rows changes for the first time. But you cannot notice this from how the program works: arrays always behave as if the copy were made right away.

Common mistake

A function trying to add an element to the array it was passed:

SWIFT
func addScore(_ list: [Int]) {
    list.append(5) // ✗
}
TEXT
error: cannot use mutating member on immutable value: 'list' is a 'let' constant

The program does not compile: the parameter is a constant holding a copy of the array. And even if it were a variable, only the copy inside the function would change. For a function to change the caller's array, you declare the parameter as inout and put & at the call:

SWIFT
func addScore(_ list: inout [Int]) {
    list.append(5)
}
addScore(&b)
print(b)  // [1, 2, 3, 4, 5]

Key points

  • An array is a value type: var b = a creates an independent copy, and changes to b are not seen in a.
  • Assignment does not empty the original array, and the copy has its own declaration: an array from a let can be copied into a var and changed.
  • A function gets a copy of an array and can change the caller's array only through inout and &.
  • Swift copies the elements right before the first change, but the program behaves as if the copy were made right away.