2

In Java, we can make an array reference immutable, and array content mutable, by using final keyword

Java

final int[] array = {1, 2, 3};
// Ok. Array content mutable.
array[0] = 9;
// Compiler error. Array reference immutable.
array = new int[]{4, 5, 6};

In Swift, they take one step further. Using let keyword, will make both array reference, and array content immutable.

Swift

let array = [1, 2, 3]
// Compiler error. Array content immutable.
array[0] = 9
// Compiler error. Array reference immutable.
array = [4, 5, 6]

In Swift, is it possible to make array reference immutable, but array content mutable?

4
  • What level of mutability do you want? Your example shows that you want to replace a value at a specific index. But do want to allow adding or removing values? Is your goal to only prevent assigning a whole new array to the "variable"? Commented Jul 10, 2019 at 4:33
  • add/remove doesn't matter. able to modify content is required. prevent assigning a whole new array to "variable" is required. Commented Jul 10, 2019 at 4:38
  • 4
    I'm not sure what the point of that would be. What's the benefit of preventing array = [4,5,6] while allowing array.removeAll(); array.append(contentsOf: [4,5,6]) ? Commented Jul 10, 2019 at 4:42
  • @rmaddy, As, we are currently porting an App from native Java to native iOS. We would like to keep to code behavior as close as possible, for easy maintenance purpose. We definitely know they are 2 different languages. They have distinct features and philosophy. We just wanna to keep them as close as possible. So, in our code which previously using final int[], direct porting to let will yield us problem as mentioned above. We want to double check from the community, to ensure we doesn't miss out any Swift trick to achieve so. Commented Jul 10, 2019 at 16:32

2 Answers 2

3

The answer for your question is "yes" and "no", depends on what you have.

If you decide to declare a simple "let" constant, you can't modify it. Why ? Because it prevents you to side effects (and you have some optimization).

For example if you just want to browse a list and print values, you don't modify the list.

myArray = [1,2,3]
for element in myArray {
  print(element)
}

Why it can be cool ? Now if you know that you don't want to modify your list, it prevents you to use functions that can modify your list. It will save your time and avoid some behavior that you don't expect. If you declare a var and you don't modify the value, Swift will tell you too.

Moreover, the concept of immutable in Swift is interesting if you use a struct or a class.

Imagine you have this structure and this class:

struct TestStruct {
  var myInt: Int

  init(myInt: Int) {
    self.myInt = myInt
  }

}

struct TestClass {
  var myInt: Int

  init(myInt: Int) {
    self.myInt = myInt
  }

}

In this structure you have myIntwhich is a var. What happens if you try to declare a TestStructure and a TestClass object with a let constant ?

let testStruct = Test(myInt: 3)
// Cannot assign to property: 'test' is a 'let' constant
test.myInt = 5
let testClass = Test(myInt: 3)
// It works
test.myInt = 5

In a struct, the let is propagated for every field, which is not the case for a class.

Sign up to request clarification or add additional context in comments.

Comments

1

Using let keyword, will make both array reference, and array content immutable.

This isn't correct. There is no "array reference" here. An array is a value, just like an integer is a value. There is no "array reference." Variables can be let or var, but that doesn't change the nature of their value. You wouldn't say that var n = 4 made "4" mutable. Similarly, var ns = [1,2,3] doesn't make [1,2,3] mutable. It just means you can change what ns refers to. Calling ns.append(5) is just like n += 1. In each case they assign a new value. They don't mutate the old value.

As an implementation and optimization detail, it is possible that the underlying array storage that was used for ns will be mutated and used for the new ns value. But this is invisible to the caller. For example:

var array = [1,2] {
    didSet { print("\(oldValue) -> \(array)") }
}
array.append(1)
array = [1,2,1]

// [1, 2] -> [1, 2, 1]
// [1, 2, 1] -> [1, 2, 1]

There's no deep difference between the append and the assignment. They are both assignments. And notice that setting the value to the same value is still just an assignment.

I'm harping on this because you can't just translate over a Java approach and have it work if your Java code relies on shared mutable state (where one part of the program modifies an array and others are supposed to have their reference update). But if your Java works that way, I recommend improving your Java to reduce its reliance on that. As long as you generally just pass values and return values, then it'll work exactly the same in Swift as in Java.

If you still need this kind of mutable array, then you can build one fairly easily by wrapping an Array in a class:

final class ArrayRef<Element>: MutableCollection, ExpressibleByArrayLiteral {
    private var elements: [Element] = []

    init(arrayLiteral elements: Element...) {
        self.elements = elements
    }

    var startIndex: Int { elements.startIndex }
    var endIndex: Int { elements.endIndex }
    func index(after i: Int) -> Int { elements.index(after: i) }

    subscript(position: Int) -> Element {
        get { elements[position] }
        set { elements[position] = newValue }
    }
}

let array: ArrayRef = [1, 2, 3]
// Ok. "Array" content mutable.
array[0] = 9
// Compiler error. "Array" is immutable.
array = [4, 5, 6]

(This is a very simple and unoptimized implementation. With more work you can make it more efficient and improve the interface.)

But I don't particularly recommend this unless you really need it. There's a reason it doesn't exist in stdlib.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.