Mehul Parmar
Mehul Parmar

Reputation: 3699

Mutating a struct in its subscript getter

While playing with structs, I discovered the following:

struct SomeStruct {
    private(set) var uncount: Int
    subscript(i: Int) -> Int {
        uncount = i  // <--'self' is immutable-----
        return 3
    }
}

let someStructInstance = SomeStruct(uncount: 3)
someStructInstance[345]

The above code does not compile, because 'self is immutable', and you can't add mutating keyword to the subscript.

However, the following works perfectly:

struct SomeStruct {
    private(set) var uncount: Int
    subscript(i: Int) -> Int {
        get {
            return 3
        }
        set {
            uncount = i  //<--works well now---
        }
    }
}

let someStructInstance = SomeStruct(uncount: 3)
someStructInstance[345]

The question: when both the subscript functions mutate the struct property, why does one work, but not the other ?

Upvotes: 2

Views: 1597

Answers (1)

Martin R
Martin R

Reputation: 539965

Your

subscript(i: Int) -> Int {
    uncount = i  // <--'self' is immutable-----
    return 3
}

defines only a subscript getter, and that is non-mutating by default.

If you really need to mutate the property in the getter then you can declare it as mutating get:

subscript(i: Int) -> Int {
    mutating get {
        uncount = i
        return 3
    }
}

As a consequence, the getter cannot be used with a constant value anymore,

let someStructInstance = SomeStruct(uncount: 3)
print(someStructInstance[345])
// error: Cannot use mutating getter on immutable value: 'someStructInstance' is a 'let'

it has to be a variable:

var someStructInstance = SomeStruct(uncount: 3)
print(someStructInstance[345])     // 3
print(someStructInstance.uncount)  // 345

Upvotes: 9

Related Questions