Home > Mobile >  Defining concrete associatedtype but I still can't use protocol as variable
Defining concrete associatedtype but I still can't use protocol as variable

Time:05-31

I would like to use SendMessageUseCase as a variable type, for example var sendMessageUseCase: SendMessageUseCase but I can't.

I keep getting the error Protocol 'SendMessageUseCase' can only be used as a generic constraint because it has Self or associated type requirements

Which obviously I understand the error but it doesn't make sense.

In SendMessageUseCase I have defined my associated type using Where clause which means technically the compiler should be able to infer, since I have explicitly defined Input and Output to be SendMessageUseCaseInput and SendMessageUseCaseOutput respectively.

protocol UseCaseInput {}
protocol UseCaseOutput {}
protocol UseCase : AnyObject {
    associatedtype Input: UseCaseInput
    associatedtype Output: UseCaseOutput
    
    func execute(input: Input, _ completion: (_ output: Output) -> ())
}

struct SendMessageUseCaseInput : UseCaseInput {
    var text: String
}

struct SendMessageUseCaseOutput: UseCaseOutput {
    var response: String
}

protocol SendMessageUseCase: UseCase where Input == SendMessageUseCaseInput, Output == SendMessageUseCaseOutput {
    
}

final class TestSendMessageUseCase : SendMessageUseCase {
    func execute(input: SendMessageUseCaseInput, _ completion: () -> ()) {
        
    }
}

// Why this doesn't work?
var sendMessageUseCase: SendMessageUseCase = TestSendMessageUseCase()

can SendMessageUseCase.Input be anything else other than SendMessageUseCaseInput? I don't think so which is why I think it should be inferd. But obviously I am wrong and can't understand why.

CodePudding user response:

Thanks to a comment from @Jessy I was able to come to a temporary solution.

Adding some to the sendMessageUseCase variable would allow us to use opaque type but there is still a limitation as you can not have an array.

There are some talks to implement this but as of now (May, 28 2022) it still hasn't been implemented.

protocol UseCaseInput {}
protocol UseCaseOutput {}
protocol UseCase : AnyObject {
    associatedtype Input: UseCaseInput
    associatedtype Output: UseCaseOutput
    
    func execute(input: Input, _ completion: (_ output: Output) -> ())
}

struct SendMessageUseCaseInput : UseCaseInput {
    var text: String
}

struct SendMessageUseCaseOutput: UseCaseOutput {
    var response: String
}

protocol SendMessageUseCase: UseCase where Input == SendMessageUseCaseInput, Output == SendMessageUseCaseOutput {
}

final class TestSendMessageUseCase : SendMessageUseCase {
    func execute(input: SendMessageUseCaseInput, _ completion: (SendMessageUseCaseOutput) -> ()) {
        
    }
    
}

var sendMessageUseCase: some SendMessageUseCase = TestSendMessageUseCase()

If anyone is interested here are the forum threads

Lifting the “Self or associated type” constraint on existentials

[ [Sema]AST][WIP] Support existentials with concrete assoc. types #21576 (PR is closed)

  • Related