# Use `var` in `struct` in Swift **TL;DR**: Use `var` for properties in `struct` as long as it serves as a *nominal tuple*. In most cases, there is no obvious benefit to using `let` for `struct` properties. ## Simple Example Let's start with a simple example: ```swift struct MyStruct { let name: String } ``` When using a `struct` as a *nominal tuple*, a term from type theory meaning a tuple where each field is identified by its name, there are no strong reasons to prefer `let` over `var`. The intention behind using `let` might be to prevent accidental changes, making the property immutable. However, this immutability is not absolute due to Swift's `mutating` behavior. Here's an example: ```swift extension MyStruct { mutating func setName(_ newName: String) { self = .init(name: newName) } } ``` Someone can write this code without your knowledge somewhere in the code base. Even though `name` is declared with `let`, you can still mutate it if `MyStruct` itself is declared as `var`: ```swift var test = MyStruct(name: "test") // test.name = "modified" // This is not possible. test.setName("modified") // But this is possible. print(test.name) // Output: "modified" ``` Thus, if a `struct` value is declared as `var`, it can be mutated regardless of whether the properties are declared with `let` or `var`. Conversely, if the value is declared as `let`, no mutation is possible, and the compiler will prevent the use of `setName(_:)`. ### Example of API Response Struct Consider an API response `struct` where we use `let` to "feel safe": ```swift struct User: Codable { let name: String let nicknames: [String] } ``` However, this perceived safety can be circumvented: ```swift extension User { mutating func addNickname(_ newNickname: String) { var newNicknames = nicknames newNicknames.append(newNickname) self = .init(name: name, nicknames: newNicknames) } } ``` The following code demonstrates this: ```swift var user = User(name: "test", nicknames: ["alpha", "beta"]) user.addNickname("charlie") print(user.nicknames) // Output: "alpha", "beta", "charlie" ``` In this example, you might realize that `addNickname(_:)` is actually useful for implementing an application feature. Using `let` does not prevent mutability in practice, and it can add unnecessary complexity. If the stored properties were `var`, this code could be much simpler, and in some cases, an explicit `addNickname(_:)` might not even be needed: ```swift struct User: Codable { var name: String var nicknames: [String] } var user = User(name: "test", nicknames: ["alpha", "beta"]) user.nicknames.append("charlie") print(user.nicknames) // Output: "alpha", "beta", "charlie" ``` Using `let` here adds boilerplate code, like reinitializing the `User` value, which is unnecessary and cumbersome, especially if the `struct` has more properties: ```swift func addItem(_ item: Item) { var newItems = items newItems.append(item) self = .init(a: a, b: b, c: c, ..., items: newItems) } ``` ### Strong Consistency Between Properties There are rare cases where using `let` might make sense, such as ensuring strong consistency between multiple stored properties. Consider the following: ```swift protocol Rectangle { var width: Double { get } var height: Double { get } } struct Square: Rectangle { let width: Double let height: Double init(size: Double) { width = size height = size } } ``` In this case, `width` and `height` need to remain consistent to ensure the integrity of the `Square`. However, even in this case, you could implement the consistency logic directly: ```swift struct Square: Rectangle { private var size: Double var width: Double { size } var height: Double { size } init(size: Double) { self.size = size } } ``` ### Rare Use Cases for `let` A reasonable use case for `let` is, for example, when caching a value that is computationally expensive to calculate, and you want to compute it only once: ```swift struct DataWithExpensiveHash { let data: Data let expensiveHash: String init(_ data: Data) async { self.data = data self.expensiveHash = await /* slow calculation of hash */ } } ``` However, these situations are rare compared to the typical use cases like the `User` struct. ### Conclusion In conclusion, using `let` for stored properties in `struct` provides no obvious benefits in most cases and often introduces unnecessary complexity. Therefore, I recommend using `var` for `struct` properties, especially when the `struct` functions as a *nominal tuple*. Note: This discussion only applies to value types (`struct`). For reference types (`class`), the considerations are different, and using `let` by default is generally advisable.