var absences = [0, 2, 0, 4, 0, 3, 1, 0]
let midpoint = absences.count / 2
var firstHalf = absences.prefix(upTo: midpoint)
let secondHalf = absences.suffix(from: midpoint)
Quotation from Apple:
Neither the firstHalf nor secondHalf slices allocate any new storage of their own. Instead, each presents a view onto the storage of the absences array.
When I try to mutate firstHalf
as the following:
firstHalf[1] = 19
the values of firstHalf
changes but the original array absences
remains the same (firstHalf[1]
is equal to 19 while absences[1]
equals to 2)
So what happens in the background. Did I instantiate a new array by mutating the array slice?
Thanks in advance.
Yes, the standard library's collection types, including
Array
andArraySlice
, all have copy-on-write behaviour. This means that they can share storage of their elements with other collections until they are mutated, in which case they will take their own copy of them.In your case, the underlying array buffer that the slice
firstHalf
has a view onto is non-uniquely referenced (as bothabsences
&secondHalf
also have a view onto it). Therefore when you go to mutatefirstHalf
, a copy is triggered – creating a new buffer containing the elements of the slice (but not necessarily the entire array).firstHalf
now has a unique view onto this new buffer, withabsences
&secondHalf
both sharing a view onto the old array buffer. ThereforefirstHalf
can now mutate the elements of its buffer without affecting the elements of the original array, thus preserving value semantics.This is the standard copy-on-write behavior employed behind the scenes by Swift collections, where it doesn't copy the collection until you attempt to mutate it. For discussion of copy-on-write, see WWDC 2015 video Building Better Apps with Value Types in Swift.
The comments in the code clarify this for us: