Vive Vive - 1 month ago 10
Swift Question

Unable to use indices.contains() in a Collection extension in Swift 3

I wrote following extension in Swift 2.3:

extension CollectionType {
/// Returns the element at the specified index iff it is within bounds, otherwise nil.
subscript (safe index: Index) -> Generator.Element? {
return indices.contains(index) ? self[index] : nil
}
}


However, it turns out that Swift 3.0 does not have
contains()
function. Instead, it offers me following syntax for this method:

indices.contains(where: { (<#Self.Indices.Iterator.Element#>) -> Bool in
<# code ??? what should it do??? #>
})


The problem is that I don't know what should it contain inside the block. Any help with migrating it, please?

Answer

The Sequence protocol in Swift 3 still has a contains(_:) method – the problem you're encountering is due to the change in the type of Collection's indices property requirement. In Swift 2, it was of type Range<Self.Index> – however in Swift 3, it is of type Indices:

/// A type that can represent the indices that are valid for subscripting the
/// collection, in ascending order.
associatedtype Indices : IndexableBase, Sequence = DefaultIndices<Self>

As there's currently no way in Swift to constrain Indices's Iterator.Element to be of type Self.Index (this will however be possible in a future version of Swift), there's no way for the compiler to know that the elements of the indices are Equatable (which is required for the use of the contains(_:) method).

Therefore you can simply constrain your extension so this is the case:

extension Collection where Indices.Iterator.Element == Index {

    /// Returns the element at the specified index iff it is within bounds, otherwise nil.
    subscript (safe index: Index) -> Generator.Element? {
        return indices.contains(index) ? self[index] : nil
    }
}
Comments