Cannot specialize protocol type

1.8k Views Asked by At

Swift5.7 came with primary associated type. I try with these codes, But it shows up with error: Cannot specialize protocol type 'GenericDelegate'

class BaseResponse {}
class ConcreteResponse: BaseResponse {}

protocol GenericDelegate<Response>: AnyObject {
    associatedtype Response: BaseResponse
    func didGetResponse(response: Response)
}


class BaseCGI<T:BaseResponse> {
    weak var delegate: (any GenericDelegate<T>)? //error: Cannot specialize protocol type 'GenericDelegate'

    func didGetResponse(response: T) {
        self.delegate?.didGetResponse(response: response)
    }
}

How can we make an existential type with a specified associated type become a variable?

Use like this:

class FooDelegate: GenericDelegate {
    func didGetResponse(response: ConcreteResponse) {
        //do something
   }

}

let cgi = BaseCGI<ConcreteResponse>()
cgi.delegate = FooDelegate()
cgi.didGetResponse(response: ConcreteResponse())

2

There are 2 best solutions below

0
On

As I see it you must make your class BaseCGI generic over both the response type and the delegate type. Further you need to tell the compiler that the response type for the delegate is the same as the response type for the class

class BaseCGI<Response: BaseResponse, Delegate: GenericDelegate> where Delegate.Response == Response {
    weak var delegate: Delegate?

    func didGetResponse(response: Response)  {
        self.delegate?.didGetResponse(response: response)
    }
}

Then you create an instance like

let cgi = BaseCGI<ConcreteResponse, FooDelegate>()
0
On

GenericDelegate has an associated type Response that must conform to BaseResponse and when you write:

weak var delegate: (any GenericDelegate<T>)?

it seems you want a GenericDelegate with Response == T.

The easiest way to do that is probably:

class BaseCGI<D: GenericDelegate> { 
    weak var delegate: D?

    func didGetResponse(response: D.Response) {
        self.delegate?.didGetResponse(response: response)
    }
}

let cgi = BaseCGI<FooDelegate>()
cgi.delegate = FooDelegate()
cgi.didGetResponse(response: ConcreteResponse())