It has recently come to my attention that the slicing subscript on MutableCollection
is { get set }
. As in, it can be assigned to.
The documentation for MutableCollection
states:
However, since slices are settable, we can currently write code like this:
extension MutableCollection {
mutating func swapSubranges<R: RangeExpression, S: RangeExpression>(_ a: R, _ b: S)
where R.Bound == Index, S.Bound == Index
{
(self[a], self[b]) = (self[b], self[a])
}
}
This compiles, and can be called with ranges of different length:
var x = [1, 2, 3, 4]
x.swapSubranges(0...0, 2...)
print(x) // [3, 4, 1] It got shorter!
Note that the “2” was overwritten, despite being located outside both subranges, and the length of the collection changed despite calling only MutableCollection
methods.
In fact we can even make it longer than it was originally:
x.swapSubranges(0...1, 2...)
print(x) // [1, 1, 3, 4]
x.swapSubranges(0...1, 3...)
print(x) // [4, 3, 4, 1, 1]
Is this behavior known?
Is it intentional?
Should the the slicing subscript be get-only here?