var a = [1,2,3]
var b = [: 2,3,4 :]
func arrayConsumer(arg: [Int]) {}
Under the proposed semantics, arrayConsumer(a) would make arg an immutable variable referencing a mutable array (So assigning to arg[x] would be permitted), while arrayConsumer(b) would make arg an immutable variable referencing an immutable array (So assigning to arg[x] would be forbidden).
The proposed solution is not just a matter of syntax but of types: a and b would not be compatible. So a would have type [Int] and b would have type [:Int:]. You simply couldn't pass b into arrayConsumer without explicitly noting the change:
arrayConsumer(b.immutableCopy())
Similarly, if you had a function that expected a mutable array, you would not be able to pass a in without making a mutable copy of it.
Yes, you could propagate the mutability to argument types (your syntax is the opposite of the one proposed by the OP, not that this matters to your argument), but that’s a lot of syntactic epicycles, all to deal with the top level of one collection type. Why is it so important to have this for Arrays, and not for Hashes, or for objects, for that matter?
The Swift view, as I understand it, is that there are some types (
“struct” instances and scalars) passed with value semantics, and some types (“class” instances) passed with reference semantics, and Arrays were reclassified from being the latter to being the former. This seems to me a sensible way of targeting the common case (passing arrays in Cocoa is quite common, but passing mutable arrays is extremely rare) without burdening the language with a full set of C++ style const designations.