How do you conform to this Protocol in Swift 5.7?

This protocol is just invented by me to make sense of generics an associated types. Not sure how to write a class/struct that conforms to it. Thanks!

protocol MyProto<T> {

associatedtype T: Sequence<Int>

func myFunc(a: T)

}

Here are a few ways to make a type conform to MyProto.

You can conform by picking a specific type for T that satisfies the constraint. (The constraint is that T must conform to Sequence and its Element must be Int.) Then write an implementation of myFunc that takes an argument of that specific type. Example:

struct MyStruct: MyProto {
    // Set conforms to Sequence.
    typealias T = Set<Int>

    func myFunc(a: Set<Int>) {
        print("\(a.count)")
    }
}

You can also make an existing type conform this way, using an extension on the existing type. For example:

extension String: MyProto {
    // Range conforms to Sequence.
    typealias T = Range<Int>

    func myFunc(a: Range<Int>) {
        print("\(self) \(a)")
    }
}

Another way to conform is to create a generic type, and then make the generic type conform only when its generic parameter satisfies the constraint. Example:

struct MyGenericStruct<T> { }

extension MyGenericStruct: MyProto where T: Sequence<Int> {
    func myFunc(a: T) {
        print("\(a)")
    }
}

This is called a conditional conformance, because MyGenericStruct only conforms to MyProto if its T parameter satisfies the constraint.


If your type always constrains T, it can conform unconditionally, like this:

struct MyLessGenericStruct<T: Sequence<Int>> { }

// T always satisfies the MyProto constraint, so this
// conformance is unconditional.
extension MyLessGenericStruct: MyProto {
    func myFunc(a: T) {
        print(a)
    }
}

You can also make an existing generic type conform to MyProto. Usually this will be a conditional conformance. Example:

extension Array: MyProto where Element: Sequence, Element.Element == Int {
    typealias T = Element

    func myFunc(a: T) {
        let found = self.contains { $0.elementsEqual(a) }
        print(found)
    }
}

You can also conform if you have a generic parameter that conforms, by using your parameter's conformance to implement your own conformance.

extension Set: MyProto where Element: MyProto {
    typealias T = Element.T

    func myFunc(a: T) {
        self.first?.myFunc(a: a)
    }
}

Please note that in many of these examples, I have explicitly defined T using a typealias. But often Swift can infer T from the type of a property or function. For example, we could write that last example like this instead:

extension Set: MyProto where Element: MyProto {
    func myFunc(a: Element.T) {
        self.first?.myFunc(a: a)
    }
}

Swift sees that myFunc can satisfy the MyProto requirement if T is Element.T, and doesn't find any contradictory declarations, so it infers T = Element.T.

2 Likes