// For example, in the case that
// you want to add 1 to the last element of an array of integers...
var integers = [0, 1, 2, 3, 4, 5]
WAY_1: do {
guard let last = integers.popLast() else { fatalError() }
integers.append(last + 1)
}
WAY_2: do {
integers[integers.endIndex - 1] = integers.last! + 1
}
However, I want something like this:
integers.last! += 1 // Impossible in current Swift.
extension MutableCollection where Self: BidirectionalCollection {
var mutableLast: Element {
get { last! }
set { self[index(before: endIndex)] = newValue }
}
}
This works on other collections other than Array as well, as long as it has last and index(before:) (aka. BidirectionalCollection) and a mutable subscript setter for an index (aka. MutableCollection)
This made me wonder why last is not settable. Does anyone know? The code so far in this thread uses implicitly-unwrapped optionals but I think setting to nil should just remove the last element.
Is there any way to actually add just a setter? You can access "super.get" like this, with the code below, but you'll get disambiguation errors if you try to use it…
var last: Element? {
get {
let `self`: some BidirectionalCollection<Element> = self
return `self`.last
}
…so you need some kind of stupid name instead, that is not last:
public extension BidirectionalCollection where Self: MutableCollection & RangeReplaceableCollection {
/// Adds the `set` accessor to the `last` property.
var last_set: Element? {
get { last }
set {
switch (isEmpty, newValue) {
case (false, let newValue?): self[index(before: endIndex)] = newValue
case (false, nil): removeLast()
case (true, let newValue?): append(newValue)
case (true, nil): break
}
}
}
}
And, for symmetry, setting first to nil should trigger "array.remove(at: 0)" ?
We can have special "start / end" markers:
array.last = nil // compile time error, value is non optional
array.last = value // ok if array is not empty, runtime error if array is empty
array.first = nil // compile time error, value is non optional
array.first = value // ok if array not empty, runtime error if array is empty
array.start = nil // removes the first element, runtime error if array is empty
array.start = someValue // inserts a new element at zero
array.end = nil // removes the last element, runtime error if array is empty
array.end = someValue // appends a new element
OTOH, getters for start/end markers would make no sense. Which suggests they should be methods rather than vars. And "array.start = nil / val" is hardly nicer than "removeFirst" / "prepend(val)".
Perhaps I wasn't clear. I see no problem of having first and last mutable vars to allow for "array.last += 1", etc. I do see a problem with an API where "last = value" either changes the last entry or appends depending upon if array is empty or not, or, equally, that I can append to array via "last" but not prepend to array via "first" → hence the above attempt to split the two concepts first/last and start/end - the latter used exclusively for the purposes of appending / prepending and shrinking from either side - but then came to the conclusion that in that case they should be just methods.