Conforming to a protocol with an associatedtype that has associatedtypes

I'm attempting to create protocols to abstract Alamfire's request -> response pipeline to create a generic relationship between the two. Abstractly, the types look like this:

struct DataResponse<Success, Failure: Error> {}
final class DataRequest {}
enum AFError: Error {}

protocol PublishableRequest {
    associatedtype Response: PublishedResponse
}

protocol PublishedResponse {
    associatedtype Success
    associatedtype Failure: Error
}

extension DataResponse: PublishedResponse {}

extension DataRequest: PublishableRequest {
    typealias Response = DataResponse
}

Despite the fact that DataResponse conforms to PublishedResponse, type alias Response = DataResponse isn't enough to conform to the protocol, the compiler continuously complains that there's no inner type Response. Is there a way to express the typealias to conform to the protocol?

You can make DataRequest generic first. Then do the conformance.

struct DataResponse<Success, Failure: Error> {}
final class DataRequest<Success, Failure: Error> {
  typealias Response = DataResponse<Success, Failure>
}
enum AFError: Error {}

protocol PublishableRequest {
    associatedtype Response: PublishedResponse
}

protocol PublishedResponse {
    associatedtype Success
    associatedtype Failure: Error
}

extension DataResponse: PublishedResponse {}

extension DataRequest: PublishableRequest {}

Thanks. Your solution works but making DataRequest generic isn't possible. It's part of Alamofire's public API, and since requests can have multiple responses depending on parsing, it's not a requirement we'd want anyway. I do find it odd that the compiler accepts the definition of the typealias in my example, but can't use it to fulfill the protocol requirement.

Isn't Swift totally right here?

DataResponse is not a type, it's a family of types. For example, DataResponse<Int, NIO.IOError> is one possible DataResponse. DataResponse<CGFloat, Network.NWError> is another.

This means that when your DataRequest extension says that Response = DataResponse, Swift doesn't know which DataResponse you mean. There is type information missing here.

I think this is probably a compiler error checking bug. The actual issue is that you haven't specified a type that actually exists for the typealias, but Swift hasn't noticed this.

That's fine, you should just say what the DataResponse types are for DataRequest.

1 Like

You're right, there's no way to define the actual type with DataRequest. I could use the protocol to define one specific type, but I think I'm going to explore the problem space more before trying to come up with a single abstraction. This is all for my Combine work on Alamofire, so perhaps the publisher could provide the types necessary here, but I can start by making them concrete.