Dear Erica: How do I create a visible, non-mutable array?

Marc writes, that he wants an array that’s modifiable internally but visible to the outside world. “But don’t they get a pointer to an array object and they can append to it? I just ended up making a getter that make a copy of a private var myArray = [Object]“.

Say you have the following class code in a module. It’s a simple class that has an array and a public  function that adds twos to the array on each call. Call it ten times, you end up with an array containing ten twos. It’s not a very interesting class but it does showcase an interesting Swift behavior.

public class MyClass: DefaultReflectable {
    public var array: [Int] = []
    public func modifyArray() { array += [2] }
    public init() {}

If you run the following code from outside the module, you get the   following results. Consumers have unrestricted read-write access to that array.

let instance = MyClass() // MyClass(array: [])
instance.modifyArray() // MyClass(array: [2])
instance.array = [3] // MyClass(array: [3])
instance.array.append(4) // [3, 4]

You need a simple edit, which adjusts access to the array setter, as shown here.

public internal(set) var array: [Int] = []

This creates two access levels, public, except in the case of set, in which case the access control is internal.

Making this one change enables you to change this behavior and disallow the last two lines in the preceding example, the final two lines that applied array edits. With an internal access level for the setter consumers won’t be able to directly change the array except through your provided API. The final two lines of code no longer compile, raising the errors you’d expect from a let constant instead of a variable:

let instance = MyClass() // MyClass(array: [])
instance.modifyArray() // MyClass(array: [2])
instance.array = [3] // error, Cannot assign to property, 'array' setter is inaccessible
instance.array.append(4) // error, cannot use mutating member on immutable value

Like my posts? Consider buying a book.

Comments are closed.