Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

private(set) raises 'self' is immutable within struct

I don't know if I am just too tired, but I think there is more to it. (I tried two cups of coffee, but still couldn't solve the problem...)

I want to make a variable read-only from the outside, but writable through methods. (So like in that example I can make sure favoriteNumber is only single-digit.

(I don't want to make it a computed property and do that in get {}, set{}, because in my other project I want to modify the variable based on a value different than "newValue" of set {})

struct Person {

    var name: String
    private(set) var favoriteNumber: Int? // Should only be single-digit

    init(name: String, number: Int) {

        self.name = name

        // Make sure favorite number is single-digit
        guard number >= 0 && number < 10 else {
            self.favoriteNumber = nil
        }
        self.favoriteNumber = number
    }

    func changeFavoriteNumber(number: Int) {
        guard number >= 0 && number < 10 else { return }
        self.favoriteNumber = number
    }
}

.

The line

self.favoriteNumber = number 

in the function

changeFavoriteNumber(number:)

raises the error

"Cannot assign to property: 'self' is immutable"

and suggests "Mark method 'mutating' to make 'self' mutable". But that's not what I want, since I don't want to modify an instance of type Person, but a mutable variable... (var favoriteNumber)

Supposed to be used in that way:

let frank = Person.init(name: "Frank", number: 9)
frank.changeFavoriteNumber(number: 8)

I have no idea what's going on here (even after 3 coffees now :)

like image 945
Tysac Avatar asked Feb 12 '18 19:02

Tysac


People also ask

Why struct is immutable in Swift?

Structs are not copied on mutation. They may be mutated in-place. But every variable is a new copy (including passing the struct value as a function parameter). In functional languages values are truly immutable (so in order to change oven's temperature you need create a new oven in a new kitchen in a new house).

Are C# structs immutable?

A struct type is not immutable. Yes, strings are. Making your own type immutable is easy, simply don't provide a default constructor, make all fields private and define no methods or properties that change a field value. Have a method that should mutate the object return a new object instead.

Is immutable SwiftUI?

SwiftUI views are structs. Structs are immutable by default (so the values inside are immutable too) Methods (functions) marked with mutating can mutate the values of properties. But that's not allowed in SwiftUI, because it uses a computed property.

What is class and struct in Swift?

In Swift, structs are value types whereas classes are reference types. When you copy a struct, you end up with two unique copies of the data. When you copy a class, you end up with two references to one instance of the data. It's a crucial difference, and it affects your choice between classes or structs.


1 Answers

Structs are value types, and have different semantics than classes. A variable storing an instance of a class is stored as a reference to the actual object elsewhere in memory; this means that you can have two variables pointing to the same object, and you can modify a class's members whether or not the variables referencing it are mutable.

A struct is different. A variable storing an instance of a struct stores the struct's members directly, instead of as a reference to an object somewhere else. This means that passing a struct to a function or another variable creates a copy of it, and modifying a struct directly modifies the variable storing it.

Therefore, a struct is immutable unless it's stored in a var. Functions that mutate the struct must be declared mutating as the compiler suggests, so that the compiler can enforce that only non-mutating functions are called on let structs.

like image 161
NobodyNada Avatar answered Oct 21 '22 20:10

NobodyNada