I am currently trying to update a custom collection type to Swift 4.1.
However, when I adhere to the documentation and implement all requirements for Collection and RangeReplaceableCollection, Xcode is still complaining that my type does not conform to RangeReplaceableCollection.
Here's an mcve for the problem (generously provided by Hamish, thank you for that :)
class Foo<Element : AnyObject> {
required init() {}
private var base: [Element] = []
}
extension Foo : Collection {
typealias Index = Int
var startIndex: Index {
return base.startIndex
}
var endIndex: Index {
return base.endIndex
}
func index(after i: Index) -> Index {
return base.index(after: i)
}
subscript(index: Index) -> Element {
return base[index]
}
}
extension Foo : RangeReplaceableCollection {
func replaceSubrange<C : Collection>(
_ subrange: Range<Index>, with newElements: C
) where Element == C.Element {}
}
According to the documentation, the code should compile:
To add RangeReplaceableCollection conformance to your custom collection, add an empty initializer and the replaceSubrange(_:with:) method to your custom type. RangeReplaceableCollection provides default implementations of all its other methods using this initializer and method.
Unfortunately though, it doesn't. Instead, Xcode emits the following error message:
// error: type 'Foo<Element>' does not conform to protocol 'RangeReplaceableCollection'
// extension Foo : RangeReplaceableCollection {
// ^
// Swift.RangeReplaceableCollection:5:26: note: candidate has non-matching type '<Self, S> (contentsOf: S) -> ()' [with SubSequence = Foo<Element>.SubSequence]
// public mutating func append<S>(contentsOf newElements: S) where S : Sequence, Self.Element == S.Element
// ^
// Swift.RangeReplaceableCollection:9:26: note: protocol requires function 'append(contentsOf:)' with type '<S> (contentsOf: S) -> ()'; do you want to add a stub?
// public mutating func append<S>(contentsOf newElements: S) where S : Sequence, Self.Element == S.Element
//
To make sure it's not an error in the documentation, I checked the source code of Swift 4.1 and found the default implementation of func append<S>(contentsOf newElements: S) where S: Sequence, Element == S.Element in RangeReplaceableCollection.swift, lines 442-452:
@_inlineable
public mutating func append<S : Sequence>(contentsOf newElements: S) where S.Element == Element {
let approximateCapacity = self.count + numericCast(newElements.underestimatedCount)
self.reserveCapacity(approximateCapacity)
for element in newElements {
append(element)
}
}
Question:
- Why does Xcode ask for an implementation of this function although a default implementation is provided?
- How do I get my code to compile?
` and `func append– Hamish Apr 13 '18 at 13:21` it compiles (it also compiles if you mark the class as `final` or are in Swift 4.0.3). Looks like the generic placeholder in the requirement is the problem. By the looks of the error message I think this could actually be related to the change discussed in https://stackoverflow.com/q/49792626/2976878.... I'll file a bug when I get a moment.