Last active
April 12, 2016 22:08
-
-
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 file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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 |
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
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