Hello Swift community! I'm here to discuss a new idea. I'm sorry if it was already discussed but if this was the case I wasn't able to find it.
I'm just suggesting the possibility to mutate the elements of an array inside for-in loops (and other flows maybe).
Basically my idea is to change this:
var dogs: [Dog] = //...
for (offset, dog) in dogs.enumerated() {
if dog.age > 1 {
dogs[offset].description = "grown"
}
}
To this:
var dogs: [Dog] = //...
for inout dog in dogs {
if dog.age > 1 {
dog.description = "grown"
}
}
Parts of that vision for ownership are being reviewed even right now, with recent proposals on take and borrow. It's certainly exciting to contemplate how we might realize the remainder of that vision, including the mutating iteration feature that would very logically be spelled for inout.
For what it's worth, you can implement something like this now. Probably doesn't have everything you'd want out of a feature like this, but a good start IMO.
[update: Don't use this implementation! Use Nevin's version below.]
Don't use this
extension MutableCollection {
func modifyEach(_ modify: (inout Element) throws -> Void) rethrows {
for index in indices {
modify(&self[index])
}
}
}
var ints = Array(1...10)
ints.modifyEach { $0 += 1 }
…and of course, since somebody has to say it, “You shouldn’t iterate over indices while modifying a collection, because that can cause an unwanted copy-on-write if indices holds a reference to the collection (as is the case with Dictionary.Values, for example).”
The right way to do this is:
extension MutableCollection {
mutating func modifyEach(_ modify: (inout Element) throws -> Void) rethrows {
var i = startIndex
while i != endIndex {
try modify(&self[i])
formIndex(after: &i)
}
}
}
(Personally I lean toward naming this function transform, but that’s matter of taste.)