protocol PathCollection: Collection where Element == Target.Element, Index == Target.Index {
associatedtype Target: Collection
static var reference: KeyPath<Self, Target> { get }
}
extension PathCollection {
private var target: Target { self[keyPath: Self.reference] }
var startIndex: Index { target.startIndex }
var endIndex: Index { target.endIndex }
subscript(index: Index) -> Element {
get { target[index] }
}
func index(after i: Index) -> Index {
target.index(after: i)
}
}
It's pretty useful protocol which helps us to reduce boilerplate code when creating custom collections.
Suppose our struct wraps a dictionary. And we want it to be a collection just like that dictionary.
We should provide keyPath to the dictionary property and apply to the protocol. And it works!
Example of usage and my question:
protocol Graph: PathCollection where Target == [String: Int] {
var storage: [String: Int] { get set }
}
extension Graph {
static var reference: KeyPath<Self, [String: Int]> { \.storage }
}
struct UndirectedGraph: Graph {
typealias Element = Dictionary<String, Int>.Element // Why should we again declare this typealias!?
typealias Index = Dictionary<String, Int>.Index // Why should we again declare this typealias!?
var storage: [String: Int]
}
It perfectly works. But why should we redeclare Element and Index typealiases!? At the very first line of code of this post we explicitly defines Element and Index:
protocol PathCollection: Collection where Element == Target.Element, Index == Target.Index {
and then:
protocol Graph: PathCollection where Target == [String: Int] {
If I remove that redeclarations I get an compilation error, which I don't understand:
'PathCollection' requires the types 'Slice' and 'Dictionary<String, Int>.Element' (aka '(key: String, value: Int)') be equivalent