johnbakers
johnbakers

Reputation: 24750

Why does this compile without mutating keyword?

I feel like something is broken with the value semantics here. Consider:

struct A {
    var b = 0
    
    mutating func changeB() {
        b = 6
    }
}

struct B {
    var arr = [A]()
    
    func changeArr() {

        /* as expected this won't compile 
           unlss changeArr() is mutating:
           arr.append(A())
        */

        // but this compiles! despite that changeB is mutating!
        for var a in arr {
            a.changeB()
        }
    }
}

Why can this example mutate the struct contents without marking the function as mutating? In true value semantics, any time you change any part of the value, the whole value should be considered changed, and this is usually the behavior in Swift, but in this example it is not. Further, adding a didSet observer to var arr reveals that changeArr is not considered mutation of the value.

Upvotes: 0

Views: 43

Answers (2)

Joakim Danielson
Joakim Danielson

Reputation: 51882

The reason changeArr is not mutating is because it isn't really doing anything since it is working on local copies of the A objects. If you really want the method to do something meaningful it needs to be changed to

mutating func changeArrForReal() {
    for index in arr.indices {
        arr[index].changeB()
    }
}

Upvotes: 1

johnbakers
johnbakers

Reputation: 24750

for var a in arr {
     a.changeB()
}

This is copying an element from arr out into a and leaving arr unchanged.

If you directly access the elements inside arr via their indexes, then it will mutate and require the mutating keyword.

Upvotes: 2

Related Questions