Skip to content

Instantly share code, notes, and snippets.

@algal
Last active April 12, 2016 22:08
Show Gist options
  • Save algal/1ca25254e16504368c48 to your computer and use it in GitHub Desktop.
Save algal/1ca25254e16504368c48 to your computer and use it in GitHub Desktop.
Illustrates what is problematic about Swift's let-defined "constant" arrays actually being mutable
/*
This gist illustrates how Swift's "immutable" arrays are actually
mutable, and why that is sad. Load it into a playground to experiment.
"let"-defining an array should produce a truly immutable value. Instead, it
now produces a constant reference to a mutable, fixed-size array. This is like
C. So it is no better than C. And it's worse than Objective-C, where you
could produce a reliably constant array with code like:
NSArray * const ar = @[foo,bar,baz];
I reported this as a bug with <rdar://problem/17181951>.
Fuller discussion at <https://devforums.apple.com/message/976600#976600>.
*/
import Cocoa
//
// 1. non-constant arrays produce unnecessary aliasing problems:
//
// w is a constant array
let w:Int[] = [10,10]
// v is a constant array
let v = [w,w]
v // => [[10,10],[10,10]]
// but I am plainly allowed to mutate their contents!
v[0][0]=20
// and now I've mistakenly mutated two slots in my 2d array, because of
// the aliasing problems associated with mutability:
v // => [[20,10],[20,10]]
//
// 2. non-constant arrays undermine the purpose of the inout parameter
//
// this func takes a non-inout parameter, so I would think it cannot mutate its arguments
func mutateFirstParam(arr:Int[]) -> () {
arr[0] = 20
}
let Z:Int[] = [10,10]
Z
mutateFirstParam(Z)
Z // => surprise! Z has been changed. It was not a pure function.
//
// 3. non-constant arrays are inconsistent with Swift's constant dictionaries
//
// this dictionary is a variable, so I get to mutate it
var D = ["a":1]
D["a"]=2
D
// this dictionary is a constant, so I do not
let d = ["a":1, "b":2, "c":3]
d
d["a"] = 5 // this line produces an error, as it should
@algal
Copy link
Author

algal commented Jun 6, 2014

@aemreunal
Copy link

Using .unshare() on any array reference causes a copy to be created. For example (executed in Swift REPL):

var s1 = [1, 2]
// s1 is equal to [1, 2] (s1 = [1, 2])
let s3 = s1
// s3 points to s1 (s3 = ->s1)
s1[0] = 123
// s1 is now equal to [123, 2] (s1 = [123, 2])
s3
// prints [123, 2], because what s3 points to changed
s3.unshare()
// copies what is referred by s3, which is s1, so s3 is now [123, 2] (s3 = [123, 2])
s1[0] = 1
// s1 is now equal to [1, 2] (s1 = [1, 2])
s1
// prints [1, 2], because s1 = [1, 2]
s3
// prints [123, 2], because s3 has not changed

The above is true for mutliple references as well:

var s1 = [1, 2]
// s1 is equal to [1, 2] (s1 = [1, 2])
let s4 = [s1, s1]
// s4 points to s1 (s4 = [->s1, ->s1])
s1[0] = 123
// s1 is now equal to [123, 2] (s1 = [123, 2])
s4
// prints [[123, 2],[123, 2]], because what s4 points to changed
s4.unshare()
// copies what is referred by s4, which is s1, so s4 is now [[123, 2],[123, 2]] (s4 =  [[123, 2],[123, 2]])
s1[0] = 1
// s1 is now equal to [1, 2] (s1 = [1, 2])
s1
// prints [1, 2], because s1 = [1, 2]
s4
// prints  [[123, 2],[123, 2]], because s4 has not changed

@algal
Copy link
Author

algal commented Jun 8, 2014

I'm surprised your code above works, where you call unshare() on s3, since the Swift Programming Language says:

“You ensure the uniqueness of an array reference by calling the unshare method on a variable of array type. (The unshare method cannot be called on a constant array.)”

Excerpt From: Inc, Apple. “The Swift Programming Language.” Apple Inc., 2014-05-27T07:00:00Z. iBooks.
This material may be protected by copyright.

Check out this book on the iBooks Store: https://itunes.apple.com/WebObjects/MZStore.woa/wa/viewBook?id=881256329

@dwarfland
Copy link

FWIW, i filed a radar at: radar://17229960 "Inconsistent immutability of arrays in Swift"
and also got this tweet stream going: https://twitter.com/dwarfland/status/476310789763395584

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment