Value Types And Reference Types In Swift

When talking about object-oriented programming, most of us intuitively think about classes. In Swift, however, things are a bit different. While you can continue to use classes, Swift has a few other tricks up its sleeve that can change the way you think about software development. This is probably the most important shift in mindset when working with Swift, especially if you are coming from a more traditional object-oriented programming language like Ruby or Objective-C.

Value Types and Reference Types

The concept we tackle in this discussion is the differences between value types and reference types or, put differently, passing by value and passing by reference.

In Swift, instances of classes are passed by reference. This is similar to how classes are implemented in Ruby and Objective-C. It implies that an instance of a class can have several owners that share a copy. Instances of structures and enumerations are passed by value. Every instance of a structure or enumeration has its own unique copy of data. And the same applies to tuples.

In the remainder of this discussion, I refer to instances of classes as objects and instances of structures and enumerations as values. This avoids unnecessary complexity.

An Example

It is important that you understand the above concept so let me explain this with an example.

class Employee {

    var name = ""

}

var employee1 = Employee()
employee1.name = "Tom"

var employee2 = employee1
employee2.name = "Fred"

print(employee1.name) // Fred
print(employee2.name) // Fred

We declare a class, Employee, and create an instance, employee1. We set the name property of employee1 to Tom. We then declare another variable, employee2, and assign employee1 to it. We set the name property of employee2 to Fred and print the names of both Employee instances. Because instances of classes are passed by reference, the value of the name property of both instances is equal to Fred. Does that make sense? Or does the result surprise you?

struct Employee {

    var name = ""

}

var employee1 = Employee()
employee1.name = "Tom"

var employee2 = employee1
employee2.name = "Fred"

print(employee1.name) // Tom
print(employee2.name) // Fred

In the second example, we declare a structure, Employee, and repeat the steps of the first example. The results of the print statements is different, though.

By replacing class with struct, the outcome of the example changes in a significant way. An instance of a class, an object, can have multiple owners. An instance of a struct has one owner. When an instance of a struct is assigned or passed to a function, its value is copied. A unique instance of the struct is passed instead of a reference to the instance of the struct.

The moment employee1 is assigned to the employee2 variable, a copy of employee1 is made and assigned to employee2. The values of employee1 and employee2 have no relation to one another apart from the fact that they are copies.

Benefits of Value Types

Swift uses value types extensively. Strings, arrays, dictionaries, and numbers are value types in Swift. That is not a coincidence. If you understand the benefits of value types, you automatically understand why these types are defined as value types in Swift's standard library. What are some of the benefits of value types?

Storing Immutable Data

Value types are great for storing data. And they are even better suited for storing immutable data. Assume you have a struct that stores the balance of the user's bank account. If you pass the balance to a function, that function doesn't expect the balance to change while it is using it. By passing the balance as a value type, it receives a unique copy of the balance, regardless of where it came from.

Knowing that a value will not change is a powerful concept in software development. It is a bold promise and, if used correctly, one that value types can keep.

Manipulating Data

Value types usually don't manipulate the data they store. While it is fine and useful to provide an interface for performing computations on the data, it is the owner of the value that manipulates the data stored by the value.

This results in a control flow that is transparent and predictable. Value types are easy to work with and, another great benefit, they behave great in multithreaded environments.

Why is that? If you fetch data from a remote API on a background thread and pass the data, as a value, from the background thread to the main thread, a copy is made and sent off to the main thread. Modifying the original value on the background thread will not affect the value that is being used on the main thread. Clean, simple, and transparent.

When to Use Value Types

While I hope I have convinced you to start using value types more often, they are not a good fit for every scenario. Value types are great for storing data. If you pass around the balance of someone's account in your application, you should not be using a class instance. What you are doing is passing around a copy of the current balance of the account.

But if you need to pass around the account itself, then you want to make sure the objects that have a reference to the account are working with the same account, the same instance. If the name of the account holder changes, you want the other objects that have a reference to the account to know about it.

Value types and reference types each have their value and use. It would be unwise to choose one over the other. Andy Matuschak has a clear stance on the benefits of value types and reference types in software development and has given several presentations on the topic. Andy describes the objects of an application as a layer that operate on the value layer. That is a great way to put it.

"Think of objects as a thin, imperative layer above the predictable, pure value layer." — Andy Matuschak