Jay Imerman
Jay Imerman

Reputation: 4600

Should I use var or let for an object later mutated?

I have an iOS app that, upon startup, loads objects from persistent storage that will be manipulated later in the app. For example, on startup it loads patient profiles in an array. Does it matter if I define the items I add to the array as variables, versus constants, if they will be modified by the app later (say in a different View Controller)?

In my App Delegate, I load them like this:

func loadProfiles() {
    var profileRecord: COpaquePointer = nil
    if sqlite3_prepare_v2(db, "SELECT profilesid, objectSyncStatus, profileName, profileRelationship, profileFName, profileLName, profileAddress, profileCity, profileState, profileZip FROM profiles", -1, &profileRecord, nil) == SQLITE_OK {
        if sqlite3_step(profileRecord) == SQLITE_ROW {
            // Load profile stubs for each person
            var newProfile = DBProfile(withDatabase: db, fromRecord: profileRecord, withLanguage: appLanguage, loadAllData: false)
            patientProfiles.append(newProfile)
        }
    }
}

Of course, I get a warning that newProfile is not mutated, and it wants to change it to let newProfile = ... before it is added to the array. But, if I do that, will it become immutable later?

Thanks for the answers.

Upvotes: 2

Views: 124

Answers (2)

esthepiking
esthepiking

Reputation: 1647

The compiler is actually really good at determining whether you should use let or var, and in this case, it is correct.

var should be used anywhere the data will be mutated. For example:

  • A struct value where the properties will be mutated
  • Pointers (like your COpaquePointer)
  • Instances of classes that will be reassigned to different class instances

let should be used anywhere the data will not be mutated. For example:

  • Constants
  • Values to be added to arrays, dictionaries, arguments to functions, etc.
  • Class instances where the instance will not be reassigned.

Note that for instances of classes, you can still modify the properties of the class even if it is defined as let. var should only be used in this case when the class itself will be reassigned.

In the case of your newProfile variable, during it's lifetime it is never mutated. The object is created, then immediately appended to your array. That array needs to be defined with var because it is mutated with that append, but newProfile never gets changed. You can change the value that was appended from newProfile through the array at a later date if you'd like because the patientProfiles array is mutable.

A good practice for when you are not sure whether to use let or var is to start with let and see if the compiler complains. If it does, then change it to var.

Upvotes: 3

mixel
mixel

Reputation: 25846

I see that you do not quite understand what is constant and how it works with value and reference types.

You can think of constant as glass box with lock and key.

Once you put something in box and lock it you threw away the key so you can see box contents (read properties and call non-mutating methods) but can not change it.

Words mutated and immutable can be only applied to value types because in case of value type the box holds value itself and if some method of value can change value then it must be marked with keyword mutating so it will not be visible through box glass.

In case of reference type the box holds reference to instance of type. If you define constant of reference type then you have box with reference. You can not change the reference, but you can read it and then go and find instance by that reference and do whatever you like with that instance.

In your case you define constant:

let newProfile = DBProfile(...)

and DBProfile is class (reference type). You can not assign another reference to newProfile but you do whatever you like with object that referenced by newProfile. So you append it to patientProfiles array and you can get it later from this array and do what you want.

Upvotes: 1

Related Questions