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.