Search code examples
swiftgenericsswift-extensions

How can I make a generic Sequence Filter wrapper? Filter contains same block for both Set and Array types


I have places where I have both Set and Array of MyType.

In these places, I need to filter down my Sequences, and you'll notice that the filter block is the same for both Sequence types.

Is there any way I can implement a generic Sequence extension, where the filterFor method will return the correct type (Set or Array), depending on the receiver?

extension Set where Element: MyType {
    func filterFor(valueToMatch:String) -> Set<MyType> {
        return self.filter{
            $0.myProperty.caseInsensitiveCompare(valueToMatch) == .orderedSame
        }
    }
}

extension Array where Element: MyType {
    func filterFor(valueToMatch:String) -> [MyType] {
        return self.filter{
            $0.myProperty.caseInsensitiveCompare(valueToMatch) == .orderedSame
        }
    }
}

Solution

  • Unfortunately, no. Set has two overloads of filter(_:), with these types:

    1. func filter(_ isIncluded: (Self.Element) throws -> Bool) rethrows -> [Self.Element]
    2. func filter(_ isIncluded: (Self.Element) throws -> Bool) rethrows -> Set<Self.Element>

    The first is the implementation that satisfies the requirements of conformance to Sequence. The latter is just a method that Set implements, that isn't tied to any protocol.

    There is no generic way to reference a variant of Filter that returns anything besides Array<Self.Element>. There is a Swift Evolution proposal to fix this (SE-0174 - Change filter to return an associated type). It has been accepted, but has not been implemented yet.