Swift types
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:
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:
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.
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.
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
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.
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.
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#.
Thanks for reading! 🎉.