This is a feature is a biggest +1 for me.
I think that this feature would be incredibly helpful in particular for writing generic collection algorithms. Without this, in a generic context, algorithms use the default implementation on the protocol itself rather than the implementation provided by the concrete type itself. Consider the following example:
Let's say I have an OrderedSet collection type.
struct OrderedSet<Element>: MutableCollection { ... }
Now lets, consider the swapAt(_:_:) function on MutableCollection.
MutableCollection provides a default implementation of this function:
extension MutableCollection {
public mutating func swapAt(_ i: Index, _ j: Index) {
guard i != j else { return }
let tmp = self[i]
self[i] = self[j]
self[j] = tmp
}
}
Due to the semantics of an ordered set, this implementation does not work properly for OrderedSet. If it were used it would have not swap the elements:
var orderedSet: OrderedSet = [...]
// Indices intended to be swapped
var i: Int = ... // some index
var j: Int = ... // some other index
// Algorithm preformed by `MutableCollection`'s default
// implementation of swapAt(_:_:)
let tmp = orderedSet[i]
// Operation is not performed because cannot assign non-unique element to ordered set
orderedSet[i] = orderedSet[j]
// Since the previous assignment was not performed, the value of `tmp` is not unique
// with respect to `orderedSet` as `orderedSet[i]` remained unchanged. And as such,
// this operation is not performed for the same reason as the previous one.
orderedSet[j] = tmp
Because of this OrderedSet provides its own implementation of swapAt(_:_:).
struct OrderedSet<Element>: MutableCollection {
// ...
mutating func swapAt(_ i: OrderedSet.Index, _ j: OrderedSet.Index) {
guard i != j else { return }
// Disables uniquing of ordered set
self._enforceUniquing = false
// Because uniquing enforcement has been turned off, the following
// operations work as expected
let tmp = self[i]
self[i] = self[j]
self[j] = tmp
// Re-enables uniquing of ordered set
self._enforceUniquing = true
}
}
This implementation now works, so swapAt(_:_:) should work as expected when called on a concrete instance of OrderedSet.
var orderedSet: OrderedSet = [0, 1, 2, 3, 4]
orderedSet.swapAt(0, 4)
print(orderedSet)
// Prints "[4, 1, 2, 3, 0]"
The problem now arises when using OrderedSet with a generic algorithm on MutableCollection that calls swapAt(_:_:).
extension MutableCollection {
mutating func genericSwapAt(_ i: Self.Index, _ j: Self.Index) {
swapAt(i, j)
}
}
Since this is in a generic context, genericSwapAt(_:_:) uses the default implementation of swapAt(_:_:) rather than the implementation provided by OrderedSet. As such, genericSwapAt(_:_:) does not work as expected when called on OrderedSet.
var orderedSet: OrderedSet = [0, 1, 2, 3, 4]
orderedSet.genericSwapAt(0, 4)
print(orderedSet)
// Prints "[0, 1, 2, 3, 4]"
While the generic algorithm in the above example is fairly impractical, this has many practical implications. For example, since in-place generic sorting algorithms heavily utilize swapAt(_:_:), these algorithms don't work properly with OrderedSet. More broadly, providing custom implementations for protocol members allow conforming types to leverage their efficiencies. This is especially prevalent with custom collections as different collections have different complexities for certain algorithms. Providing their own custom implementations over default implementations allows them to meet and optimize their algorithmic complexities. While this is all well and good when calling said functions on a concrete type, all of its benefits are lost when using it in a generic context (which is extremely common with collection algorithms).
This feature would enable types to play along better with generic algorithms, and having run into this myself when creating my own custom collection, I think that this would be a welcome addition to Swift.