ProgrammingSwift Developer

What is value semantics in Swift and how to avoid unexpected data changes when passing structures and collections? How does copy-on-write differ from classic copying?

Pass interviews with Hintsage AI assistant

Answer.

In Swift, value types (struct, enum, tuple) have what is called value semantics: when passed or assigned to a variable, all contents are copied – an independent instance is created. This helps avoid several complexities with shared state, characteristic of reference types (class).

However, to optimize memory, collections (e.g., Array, Dictionary, Set) use a copy-on-write strategy: copying occurs only when one of the instances is modified.

Example:

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

Here, the array a does not change – although there was initially shared storage, when b is modified, Swift makes a separate copy of the data.

It is important to remember: if a structure contains a reference type (like a class), value semantics applies only to the structure itself, not to the nested reference objects.

Trick Question.

Will the contents of the array change if we pass it to a function and edit it inside that function? Explain the difference between the behavior of struct and class.

Answer with example:

func mutate(_ arr: inout [Int]) { arr.append(100) } var source = [1, 2] mutate(&source) print(source) // [1, 2, 100]

If passed without inout, copying occurs automatically at the first modification inside the function, and the original array will not change. For classes, copying does not happen – the original object will always change.

Examples of real mistakes due to lack of understanding of the topic.


Story

Developers stored reference objects in an array of structures (struct), expecting that changes through one structure would not affect other instances. In reality, modifying reference objects in one place unexpectedly changed them everywhere (shared state).


Story

In a team project, they attempted to achieve protection against race conditions by copying collections on every access. This caused unforeseen memory overhead and performance drops when working with large arrays.


Story

A young developer tried to track changes in an array, which led to passing it by inout to several handler functions simultaneously. The order of modifications became unclear, leading to thread-unsafe changes, bugs, and synchronization errors.