Search code examples
genericsswiftprotocolstype-constraintstype-variables

Swift Generic Type Variable should comply to a Protocol (type class)


I am trying to write a helper function in swift, that allows to sort more conveniently. Here is what I have and what works:

someArray.sorted({ someGetter($0) < someGetter($1) })

Instead I would like to write

someArray.sorted(comparing(someGetter))

I was trying to define the comparing function like this

func comparing<A,B : Equatable>(f: A -> B) -> ((A,A) -> Bool) {
    return { f($0) < f($1) }
}

The problem is, that the type checker does not know, that 'B' needs to comply to the 'Equatable' protocol. I don't know how to achieve that. The compiler complains with '\'B\' is not convertible to \'UInt8\'', because it assumes two Ints to be compared by the '<' function. If I overwrite '<' for example with:

@infix func <(lhs: SomeType, rhs: SomeType) -> Bool {
    return lhs.i < rhs.i
}

then the compiler assumes SomeType instead of UInt8.

This is my second day playing around with Swift. I hope my question is not too stupid. I will probably have a bunch of other mistakes as well.

Thank you!


Solution

  • I'm not quite sure why you need B to be Equatable - since you're comparing the values, you only need them to be Comparable:

    func comparing<A, B: Comparable >(f: A -> B) -> (A,A) -> Bool {
        return { f($0) < f($1) }
    }
    

    If you do need B to conform to both Equatable and Comparable, you can use a where clause to add additional constraints:

    func comparing<A, B: Comparable where B: Equatable>(f: A -> B) -> (A, A) -> Bool {
        return { f($0) < f($1) }
    }