> On Feb 7, 2017, at 8:14 PM, Guillaume Lessard via swift-users > <swift-users@swift.org> wrote: > > I keep running into weird things with Swift 3 Collections. > > A) Collection has its count property defined as an Int via IndexDistance: > > public protocol Collection : Indexable, Sequence { > associatedtype IndexDistance : SignedInteger = Int // line 182 in > Collection.swift > public var count: IndexDistance { get } // line 776 > }
This declaration specifies that the *default* associated type is Int, not that it’s *always* Int. A Collection implementation is free to use a different type as its IndexDistance if it wants. > Given this, why can’t `count` be treated as an Int? > > func intCount<C: Collection>(of c: C) -> Int { > return c.count // nope! > } > > A numericCast is required here in order to “convert” what is > known-to-be-an-Int to an actual Int. > Why this is so? IndexDistance is defined such that it must be an integer (“A > type that represents the number of steps between a pair of indices”)... > What is gained by making it so generic that it can’t simply be an Int? > > > B) Collection.Indices is a Collection of Index, *but* > - Collection.Indices.Index is not the same type as Collection.IndexDistance There’s no reason for them to be the same type for a generic Collection, just because they both happen to be Int for Array, though. > - Collection.Indices.Iterator.Element is somehow not the automatically the > same type as Collection.Index > (ugh) I think you’re right that this is a generics limitation - we’re waiting on ‘where clauses for associated types’ to make these two types equivalent. > > The second seems like a conditional conformance issue, but the first one is > baffling. > > I did find that with String.CharacterView: > String.CharacterView.Indices.Index != String.CharacterView.IndexDistance > although, as expected, > String.CharacterView.Indices.IndexDistance == > String.CharacterView.IndexDistance > (which provides an clear workaround.) > > > *** > I wanted to extend Collection with concurrentPerform; which seems simple on > the surface: > > extension Collection { > public func concurrentPerform(task: @escaping (Self.Iterator.Element) -> > Void) { > DispatchQueue.concurrentPerform(iterations: count) { > iteration in > task(self[indices[iteration]]) > } > } > } > … but that won’t do. > > The closest thing I found that does work is this: > > extension Collection { > public func concurrentPerform(task: @escaping (Self.Iterator.Element) -> > Void) { > let count: Int = numericCast(self.count) > let indexList = (0..<count).map { index(startIndex, offsetBy: > numericCast($0)) } > > DispatchQueue.concurrentPerform(iterations: count) { > iteration in > task(self[indexList[iteration]]) > } > } > } > > Note the unfortunate creation of an array of Index. > Generic Collection code is exhausting! Maybe in this case it makes more sense to define this on RandomAccessCollection or even just Array instead? Slava > > Cheers, > Guillaume Lessard > > _______________________________________________ > swift-users mailing list > swift-users@swift.org > https://lists.swift.org/mailman/listinfo/swift-users _______________________________________________ swift-users mailing list swift-users@swift.org https://lists.swift.org/mailman/listinfo/swift-users