Let and var in Swift explained

Published on: July 12, 2024

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.

Subscribe to my newsletter