Value types and reference types insights in Swift.

Swift has support for value types and reference types, but there are some cases in which these two concepts can be confuse. The aim of this article is take a tour about some special cases we can find using references and value types in Swift.

Let’s start with a quickly recap of the concepts of reference and value types.

Value type

A value type is a type whose value is exactly the data it keeps. Any assignment of a value type involves the actual data being copied.

In Swift the structs and enums are value types. Let’s see this concept in action in the following example:


struct Person {
    var name: String
    var age: Int
}

var person = Person(name: "John Doe", age: 25)
var anotherPerson = person

anotherPerson.name = "Kyle XYZ"

print(person.name) // John Doe
print(anotherPerson.name) // Kyle XYZ

In the above code we have created a struct type called Person with two properties name and age, then we have declared a person variable with the values of "John Doe" for the name property and the value of 25 for the age property.

We have declared a new variable called anotherPerson initialized with the value of the variable person. Afterwards we changed the value of the name property in the variable anotherPerson, but wait a minute; the name of the person variable has to change too isn’t? 🤔

The answer is no, because the value of theperson variable was copied when it was assigned as the initial value of the variable anotherPerson. The same happens if we pass a value type as a function parameter.

Reference type

A reference type is a type which its value it’s a reference to the data it keep rather than to the data itself. In Swift the classes and closures are reference types. Let’s see this concept in action in the following example:


class Person {
    var name: String
    var age: Int

    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

var person = Person(name: "John Doe", age: 25)

var anotherPerson = person

anotherPerson.name = "Kyle XYZ"

print(person.name) // Kyle XYZ
print(anotherPerson.name) // Kyle XYZ

We have reimplemented Person but in this case using classes. The main point here is when we changed the value of the name property in the variable anotherPerson the name property in the person variable has changed too.

When we make assignments involving reference types the concept is simple, the value which is assigned is the value of the variable, the reference itself. This mean that anytime we are going to change any property’s value of the person variable we are changing the property’s value of all the variables that share the reference.

So now we have remembered or learned what are value and reference types let’s see some special cases using reference types and value types in Swift.

Constants and variables

As you maybe should know in Swift we can have variables and constants and we can declare it using the let and var keywords respectively. Let’s see what happens with the reference types and value types when are declared as immutable or mutable instances.


struct Person {
    var name: String
    var age: Int
}

let person = Person(name: "John Doe", age: 25)

person.age = 26 // compilation error here

In the above code if we try to change the value of the property age in the previously declared constant person this throws a compilation error. The interesting point here is that in Swift once you have declared a value type as immutable every member belonging to it is immutable too. So we cannot change the values of its members anymore.

Let’s see what happens in the case of the reference types.


class Person {
    var name: String
    var age: Int

    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

let person = Person(name: "John Doe", age: 25)
person.name = "Kyle"

If you try to run the above code there is not any compilation error like in the case of the value types, this is because we have declared the person object as immutable, but only the object is immutable not its members when we use reference types. So we can change the value of its members any time even when the object is immutable. 😅

Passing reference types as parameter


class Object {}

func foo(var obj: Object?) {
    obj = nil
}

func f() {
    var x: Object? = Object()
    foo(x)
    print(x)
}

In the above code we declared a class called Object without any property, followed by a function called foo that receives as parameter an optional instance of the Object class and inside it set it value to nil. And we finish with the declaration of the function f in which we have created an variable x to pass as argument to the function foo and finally we print the value of the variable x.

So what do you think is the value of x in the print(x) statement? nil isn’t? 👍

The answer is no, it’s not the value of x, the value of x is just Optional(Object) in the print(x) statement. But wait, something weird is happening here, the reference types keeps a reference to the same existing instance, so any change in one of its references it’s reflected in all isn’t?

Uhmmm… 🤔, yes but exist a minor confussion here, as in some many programming languages like Java and C# the values are always passed-by-value, so the object isn’t the parameter. The parameter is just the variable and if you change the value of that variable, the caller won’t see that. If the parameter were really passed by reference, x would be nil afterwards. Instead, the value of x is just a reference, and that reference is passed by value.

But in Swift we have an inout keyword to explicitly say to the compiler we want that a parameter is a reference type not a copy of its reference.



class Object {}

func foo(inout obj: Object?) {
    obj = nil
}

func f() {
    var x: Object? = Object()
    foo(&x)
    print(x)
}

With the above code the value of x afterwards is nil because as we said before now the compiler knows that the value is passed-by-reference.

I hope this insights are helpful to understand a little more about the value and reference types in Swift.

Note: This article was inspired in an excellent article of Jon Skeet published in his blog about Parameter passing in C#.

*****
Written by Victor Sigler on 20 February 2016