Dan F
Dan F

Reputation: 17732

Using let on mutating variable

I have a simple custom class that for the sake of simplicity in the example lets say it contains a single property that is an array of arrays of strings. It has a single method that moves the first object from one array to another. Ignore the missing initializer, this is a truncated version of an existing class I've written.

class MyClass: NSObject
{
    var strings:Array< Array< String > >

    func makeMove(fromArray:Int, toArray:Int)
    {
        var from = strings[fromArray] as Array< String >
        var to = strings[toArray]

        let top = from[0]
        to.append(top)
        from.removeAtIndex(0)

        towers[fromTower] = from
        towers[toTower] = to
    }
}

If I declare a new instance of MyClass and call this single method on it, I get a compiler warning stating that the instance was never modified and should be made a let instead of var.

var myInstance = MyClass()    //Warning
myInstance.makeMove(0, toArray:1)


let myInstance = MyClass()    //No warning
myInstance.makeMove(0, toArray:1)

Interestingly enough, even though in the second instance it is a let, which should be a constant, the instance does in fact get mutated when makeMove is called on it.

Whats wrong in this case? Should I use a let, or is the compiler not properly recognizing that it is a mutating function?

Upvotes: 2

Views: 1907

Answers (2)

Kametrixom
Kametrixom

Reputation: 14973

To conclude, here is what I think you want, with a suggestion from wjl:

class MyClass {
    var strings : [[String]] = []

    func makeMove(fromArray from: Int, toArray to: Int) {
        let item = strings[from].removeAtIndex(0)
        strings[to].append(item)
    }
}

let a = MyClass()
a.strings = [["Hi", "H", "A", "C"], ["He", "Ab", "To", "Hehe"]]
a.makeMove(fromArray: 0, toArray: 1)
a.strings           // [["H", "A", "C"], ["He", "Ab", "To", "Hehe", "Hi"]]

// a = MyClass()    // error: cannot assign to value: 'a' is a 'let' constant

You can still change that instance of the object, but you cannot change the object, a is pointing to

Upvotes: 0

BaseZen
BaseZen

Reputation: 8718

First of all, make sure you understand reference types versus value types.

https://developer.apple.com/swift/blog/?id=10

The let keyword prevents mutation to the latter, not the former. Think of a let reference variable as: the reference (memory address) that the variable refers to cannot change, but the contents of that memory can.

So the warning is trying to tell you that you never re-assign the reference myInstance to another object, but your declaration allows for the possibility.

If your design is such that myInstance should always refer to the object it was first assigned to, let the compiler help you by denoting it as let. Then feel free to pass the reference around and change the object's contents as needed using any copy of the reference.

Upvotes: 2

Related Questions