2

I have got this code:

protocol GenericProtocol: class {
    associatedtype type
    func funca(component: type)
}

class MyType<T> {

    weak var delegate: GenericProtocol? // First error

    var t: T

    init(t: T) {
        self.t = t
    }

    func finished() {
        delegate?.funca(component: t) // Second error
    }

}

class UsingGenericProtocol: GenericProtocol {

    let myType: MyType<Int>
    typealias type = Int

    init() {
        myType = MyType<Int>(t: 0)
    }

    func funca(component: Int) {

    }

}

I want to use delegates with a given type. The code will not compile because I got this errors:

Protocol 'GenericProtocol' can only be used as a generic constraint because it has Self or associated type requirements

And:

Member 'funca' cannot be used on value of protocol type 'GenericProtocol'; use a generic constraint instead

I can omit this error by removing the type from the protocol, make it Any and then casting it to the right type, but I thought generics should cover this problem. Is there any way I can get this code to compile? Thanks.

J. Doe
  • 12,159
  • 9
  • 60
  • 114
  • Have a look at [Protocol can only be used as a generic constraint because it has Self or associated type requirements](https://stackoverflow.com/questions/36348061/protocol-can-only-be-used-as-a-generic-constraint-because-it-has-self-or-associa) – Dávid Pásztor Apr 28 '18 at 11:31

2 Answers2

3

The difference between generics and associated types is that generics are specified at instantiation, associated types during implementation. So you cannot use the protocol type as a concrete type because the associated type depends on the implementing type.

However, there are a few workarounds:

1) Use the type of the delegate as a generic type:

class MyType<Delegate: GenericProtocol> {
    typealias T = Delegate.type
    ...
}

2) Use a common protocol on your delegate method instead of an associated type:

protocol CommonProtocol { ... }

protocol DelegateProtocol {
    func funca(component: CommonProtocol)
}

3) Use closures for type erasure (this is also done in the Swift Standard Library for the Sequence protocol with AnySequence<Element>)

struct AnyGenericProtocol<GenericType>: GenericProtocol {
    typealias type = GenericType
    private let f: (GenericType) -> ()

    init<G: GenericProtocol>(_ g: GenericProtocol) where G.type == GenericType {
        f = { component in
            g.funca(component: component)
        }
    }

    func funca(component: GenericType) {
        f(component)
    }
}

class MyType<T> {
    var delegate: AnyGenericProtocol<T>
    ...
}
Palle
  • 11,511
  • 2
  • 40
  • 61
2

This is not possible to use generic protocols. Use concrete type or usual protocol instead. You have to declare concrete T outside of those abstractions

For instance, this should work:

class MyType<T> {

    weak var delegate: UsingGenericProtocol<T>? // First error

    var t: T

    init(t: T) {
        self.t = t
    }

    func finished() {
        delegate?.funca(component: t) // Second error
    }

}
class UsingGenericProtocol<T>: GenericProtocol {
    let myType: MyType<T>
    typealias type = T

    init(t: T) {
        myType = MyType<T>(t: t)
    }

    func funca(component: T) {

    }
}

let instance = UsingGenericProtocol<Int>(t: 0)
Vyacheslav
  • 26,359
  • 19
  • 112
  • 194