Mutating the properties of a struct

This.

If a struct has a memberwise initializer that

  • has the same access control of the properties
  • doesn't enforce particular invariants

then the properties should always be declared as var, and that's because if they weren't, I would still be able to reassign an instance of that struct to a variable by initializing a new one with all the same values of the properties but one.

For example, this piece of code

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

var p = Person(name: "Foo", age: 42)
p.age += 1

is (semantically) identical to this

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

var p = Person(name: "Foo", age: 42)
p = Person(name: p.name, age: p.age + 1)

the second example makes no sense, and doesn't take advantage of Swift value semantics.

The key difference from a mutable class is the following:

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

let ps = Person(name: "Foo", age: 42) // assigned to a let constant
ps.age += 1 // this is not allowed and doesn't compile

class PersonClass {
  var name: String
  var age: Int

  // it needs an explicit init
}

let pc = Person(name: "Foo", age: 42) // assigned to a let constant
pc.age += 1 // this works and compiles just fine

To me, thinking that "mutable properties" means "class" shows a fundamental misunderstanding of Swift value semantics.

5 Likes