Using Protocol as a concrete type conforming to protocol Protocol is not supported

Would anyone be able to explain why I’m getting this error (last line)? I’m not surprised I’m getting one since protocols have some gotchas I’m not familiar with, it’d just help my understanding to know why.

protocol HasInt {
    var int: Int { get }
}

struct Dependency: HasInt {
    let int = 1234
}

protocol HasDependencies {
    associatedtype Dependencies
    var dependencies: Dependencies { get }
}

extension HasDependencies where Dependencies: HasInt {
    var int: Int { return dependencies.int }
}

struct Foo: HasDependencies {
    typealias Dependencies = HasInt
    let dependencies: Dependencies
}

Foo(dependencies: Dependency()).int
// error: using 'HasInt' as a concrete type conforming to protocol 'HasInt' is not supported

A value of protocol type cannot conform to another protocol. Only concrete types can conform to protocols. This is for both semantic reasons (what if the protocol defines a static method, and you call it on type(of: value)) as well as representational (protocol values don't "fit" in the payload of another protocol value).

And here’s an epic explanation with detailed code samples, theoretical background and some workarounds.

@zoul Thanks for that link, it was really helpful.

It looks like what I'm trying to do may not be possible in swift. Since Obj-C protocols handle protocols with/without static mebers differently, adding @objc to the HasInt protocol could be a work around. Unfortunately I have other protocols for types not representable in objc.

If there are any other ways to do this, I'm open for suggestions.

I think you want:

struct Foo<Dependencies: HasInt>: HasDependencies {
    var dependencies: Dependencies
}
1 Like

Shouldn't the error happen here typealias Dependencies = HasInt and shouldn't it be a compile time error? Being an amateur, I'm just wondering…

It is a compile-time error. Also, if you remove the .int property access at the offending line, it compiles:

Foo(dependencies: Dependency())

This is because the int property access can only type-check by considering the HasDependencies extension, and that requires that Dependencies conform to HasInt. So I think the current behaviour is correct.