2

I am trying to use generic protocols in my Application. Code which I am trying to use is something like this.

protocol BaseProtocol {
  associatedtype PresenterType
  var presenter: PresenterType? { get set }
}

protocol PresenterProtocol {
  associatedtype View
  var view: View? { get set }
}

protocol ChildPresenter: PresenterProtocol where View == ChildProtocol {

}

protocol ChildProtocol: BaseProtocol where PresenterType == ChildPresenter {

}


class A: ChildProtocol {
  var presenter: ChildPresenter?
}

Compiler is throwing error while conforming to ChildProtocol

error: protocol 'ChildPresenter' can only be used as a generic constraint because it has Self or associated type requirements var presenter: ChildPresenter?

I am not getting why compiler is throwing this error when I have already cleared my associateType.

SJ3040
  • 156
  • 6
  • In case you didn't understand why you got an error, I added an explanation in my answer. – Gonzo Mar 27 '18 at 14:05
  • Does this answer your question? [Protocol can only be used as a generic constraint because it has Self or associatedType requirements](https://stackoverflow.com/questions/36348061/protocol-can-only-be-used-as-a-generic-constraint-because-it-has-self-or-associa) – Soumya Mahunt Sep 08 '22 at 06:29

1 Answers1

3

As the error says, ChildPresenter can olny be used as a generic, so you have to place it on the declaration of the class, eg. class A<T: ChildPresenter> : ChildProtocol

protocol BaseProtocol {
    associatedtype PresenterType
    var presenter: PresenterType? { get set }
}

protocol PresenterProtocol {
    associatedtype View
    var view: View? { get set }
}

protocol ChildPresenter: PresenterProtocol where View == ChildProtocol {

}

protocol ChildProtocol: BaseProtocol {

}


class A<T: ChildPresenter> : ChildProtocol {
    var presenter: T?
    func foo(bar: T) {

    }
}

You also can use ChildPresenter instead of T, like this

class A<ChildPresenter> : ChildProtocol {
    var presenter: ChildPresenter?
}

At first it seems that this limits a little bit your class A, because you have to specify the type of ChilPresenter before initialization, and it can't be modified later, but this is necessary because ChildPresenter has a associated type.

You can see that without the generic you could get into trouble, imagine that BaseProtocol had one more property

protocol BaseProtocol {
    associatedtype PresenterType
    var presenter: PresenterType? { get set }
    var presented: PresenterType? { get set }
}

Both presenter and presented have to be the same type, because you said it here

BaseProtocol declaration with Types highlighted

And class A would have one more property too:

class A<ChildPresenter> : ChildProtocol {
    var presenter: ChildPresenter?
    var presented: ChildPresenter?
}

This way, you guarantee that both presenter and presented will have always the same type, because you choose that type when you created an object of A, eg. let a = A<Foo>()

A declaration with types hightlighted

Without the generic, it would look something like this

class A: ChildProtocol {
    var presenter: ChildPresenter?
    var presented: ChildPresenter?
}

And in this way, presenter could be of type Foo and presented could be of type Bar. So you end up with a paradox. Thats why you need to set the generic type in A's declaration.

Gonzo
  • 1,533
  • 16
  • 28
  • On doing 'class A : ChildProtocol { var presenter: ChildPresenter? }' – SJ3040 Mar 29 '18 at 07:16
  • Compiler is throwing error: 'ChildProtocol' requires the types 'ChildPresenter' and 'ChildPresenter' be equivalent class A: ChildProtocol { note: requirement specified as 'Self.PresenterType' == 'ChildPresenter' [with Self = A] class A: ChildProtocol { – SJ3040 Mar 29 '18 at 07:24
  • You have to remove the `where` clause on `ChildProtocol`'s declaration – Gonzo Mar 29 '18 at 10:14