Search code examples
swiftgenericsconstraintsprotocols

SwifT: Generic function that gets generic protocol as parameter not working


Suppose I have this simple generic protocol

protocol FooProtocol {
    associatedtype Element: CustomStringConvertible

    func echo(element: Element) -> Element
}

And this simple generic struct that implements it

struct FooStruct<Element: CustomStringConvertible>: FooProtocol {
    func echo(element: Element) -> Element {
        return element
    }
}

Lastly, I have the following function:

func callEcho<T: FooProtocol>(container: T) {
    container.echo(element: "some string")
}

This results in error: cannot invoke 'echo' with an argument list of type '(element: String)'

The solution is to change the function to

func callEcho<T: FooProtocol>(container: T) where T.Element == String {
    container.echo(element: "some string")
}

My question is: why is the where T.Element == String constraint necessary? The compiler knows that T is some entity that implements FooProtocol, and the protocol only demands that Element implements CustomStringConvertible, which my string literal does. So why does it not work without the constraint?

Thanks!


Solution

  • I'm not sure why you say "the protocol only demands that Element implements CustomStringConvertible." The protocol demands that echo accept and return its Element, which may or may not be String. For example, I can implement this conforming type:

    struct AnotherFoo: FooProtocol {
        func echo(element: Int) -> Int { fatalError() }
    }
    

    So what should happen if I then call:

    callEcho(container: AnotherFoo())
    

    This would try to pass a string literal to a function that requires an Int.