Let and var in Swift explained
Virtually every programming language will have some means to define properties; Swift does too. We have two approaches to defining a property in Swift. We can use a var
or a let
. The code below shows how we can define a var
or a let
as a member of a class
:
class Member {
let id: UUID
var name: String
init(name: String) {
self.id = UUID()
self.name = name
}
}
This class has two properties. One is a let
, the other is a var
.
If you're coming from a Javascript background you might expect that there's a third option here; const
. That's not the case in Swift. Swift only has let
and var
and a let
in Swift might not be what you think it is.
A var
property is a variable. That means that whatever we assign to the var
can change over time. For example, when I make an instance of my Member
object, I can change the name
as needed:
var instance = Member(name: "Donny")
instance.name = "Hello, world!"
And because I defined instance
as a var
, I'm even able to create a new Member
and assign it to my instance
variable:
var instance = Member(name: "Donny")
instance.name = "Hello, world!"
instance = Member(name: "Oliver")
We also refer to a var
as being mutable. This is another way of saying that the value for this property can change.
A let
is the opposite. It's a constant value. This means that once we've assigned a value, we can't change it.
For example, if I define my instance
as a let
instead of a var I'm no longer allowed to assign a new value to instance
:
// notice how intstance is now defined as a let
let instance = Member(name: "Donny")
instance.name = "Hello, world!"
instance = Member(name: "Oliver") // not allowed, instance is a let
Additionally, because my Member
defined id
as a let
, I can't change that either:
let instance = Member(name: "Donny")
instance.id = UUID() // not allowed, id is a let
I can, however still change the name:
let instance = Member(name: "Donny")
instance.name = "Hello, world!"
That's because changing a property on my class instance will propagate as a change to let instance
. The class instance assigned to let instance
is still the exact same one. We just changed one of the properties.
This changes when we'd make Member
a struct:
struct Member {
let id: UUID
var name: String
init(name: String) {
self.id = UUID()
self.name = name
}
}
The properties on Member
are the exact same. The only difference is that we've made Member
a struct
instead of a class
.
I won't expand into the difference between structs and classes too much in this post, but it's important to understand that a class is assigned to a variable(var
) or constant(let
) using its address in memory. So instead of storing the actual class value in our property, we only store the location of our class instance. That's why changing a value on our instance doesn't re-assign to our let instance
in the example above.
Structs on the other hand are generally stored by value. This means that when you change a property on a struct, Swift will have to re-assign the new value to the property that's storing your instance. Let's see this in action:
let instance = Member(name: "Donny")
instance.name = "Hello, world!" // this is not allowed because `instance` is immutable
What's happening in the code above is that we've assigned a value to let instance
. When we change the name of our instance, Swift has to replace the old value of instance
with a new one because it's a struct and structs are stored using their values.
To allow mutating our instance.name
, we have to store the instance as a var
:
var instance = Member(name: "Donny")
instance.name = "Hello, world!" // this is allowed because `instance` is a variable
Now Swift is able to make a copy of our Member
with the updated name and then assign it back to var instance
.
We generally like to write our code using let
instead of var
whenever we can. The fewer properties we can change, the more predictable our code becomes, and the fewer bugs we'll ship. However, a program that never changes any of its properties wouldn't be very interesting because it'd just be a static page. So in those situations where you do need the ability to re-assign or update a property it makes sense to define that property as a var
. When in doubt, use let
. Then change it to a var
when you find that you do have a need to update that specific property later on.