Pete Barber from C#, C++, Windows & other ramblingsTake the following code:
var value: Int
let foo = [Foo(value: 1), Foo(value: 2)]
By using 'let foo' an immutable array has been created. As such no members of this array can be replaced and nor can an element's contents be modified. As such both statements below result in compilation errors.
foo = Foo(value: 777) // error!
foo.value = 8 // error!
If foo were declared var then both of the above statements would work.
This changes slightly when using reference types:
var value: Int = 0
self.value = value
let bar = [Bar(value: 1), Bar(value: 2)]
bar = Foo(value: 777) // error!
bar.value = 8 // allowed
The first case of trying to replace an element fails as before but modifying the instance referenced by that element is permitted. This is because the immutable collection holds a reference to the instance of Bar. Modifying the instance does not change the reference so the collection remains unchanged.
If you're making an effort to make your code as immutable (const) as possible (I'm from a C++ background so I endeavour to making everything as const I can) then this is a gotcha to lookout for.
The only way to make Bar properly const is to provide a private setter for the member, assuming it's defined in it's own source file (so this example doesn't work in a Plaground), i.e.
private(set) var value: Int = 0
self.value = value
value = 88;
Which now prevents value being assigned too.
let baz = [Baz(value: 1), Baz(value: 2)]
baz.value = 8 // error!
Even if all the properties have private setters there might be methods on the reference type that modify the instance, such as f() above. Just having an immutable collection of reference types is not sufficient to stop these mutating the instances referred too. Invoking f() in the above collection will change the value to 88, i.e.
println("\(baz.value)") // Gives 1
println("\(baz.value)") // Gives 88
This differs to C++ where if a collection is const or is returned as a const reference (from a method) than not only is the container immutable but so are its contents. It would be good if Swift were to gain a mechanism that would mark the collection and its contents completely immutable other than having to use a value type.
Anyway, beware of making a collection of reference types immutable and assuming that both the collection and its contents cannot be modified!