1

I have 2 protocols which inherit from one generic protocol

protocol IdentifierProtocol: Equatable, RawRepresentable {}

protocol A_IdentifierProtocol: IdentifierProtocol {}
protocol B_IdentifierProtocol: IdentifierProtocol {}

and I want to split using a function, but this code gives an error

extension UIClass {
    func myFunc<I: IdentifierProtocol>(identifier: I) where I.RawValue == String {
         if identifier is A_IdentifierProtocol { // <- Error
             print("A")
         }
         if identifier is B_IdentifierProtocol { // <- Error
             print("B")
         }
    }
}

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

How can i solve this?

EvGeniy Ilyin
  • 1,817
  • 1
  • 21
  • 38
  • So what's the error you get? – Tali Mar 22 '17 at 08:57
  • 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 08:31

1 Answers1

1

Your IdentifierProtocol is RawRepresentable, which has associatedType. And such protocol cannot be used "like if it was concrete type".

That is basically what the compilation error says:

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

Instead of duplicating information, I suggest you reading this explanation of the error you are getting: https://stackoverflow.com/a/36350283/2378431


If you want to workaround this error and still have your code working without any obvious difference (from usage perspective), you could define single method for each X_IdentifierProtocol, something like this:

protocol IdentifierProtocol: Equatable, RawRepresentable {}

protocol A_IdentifierProtocol: IdentifierProtocol {}
protocol B_IdentifierProtocol: IdentifierProtocol {}

func myFunc<I: A_IdentifierProtocol>(identifier: I) where I.RawValue == String {
    print("A: \(identifier.rawValue)")
}

func myFunc<I: B_IdentifierProtocol>(identifier: I) where I.RawValue == String {
    print("B: \(identifier.rawValue)")
}

The disadvantage is that for every X_IdentifierProtocol you need to provide one method implementation and could introduce some code duplication if you'd like to have piece of shared code based on IdentifierProtocol.


Another approach: If you really want single function, you cannot have IdentifierProtocol with associated type. However you can have multiple type constraints on generic function, something like this:

protocol IdentifierProtocol {}

protocol A_IdentifierProtocol: IdentifierProtocol {}
protocol B_IdentifierProtocol: IdentifierProtocol {}

func myFunc<I: IdentifierProtocol & Equatable & RawRepresentable>(identifier: I) where I.RawValue == String {
    if identifier is A_IdentifierProtocol {
        print("A: \(identifier.rawValue)")
    }
    if identifier is B_IdentifierProtocol {
        print("A: \(identifier.rawValue)")
    }
}

class MyClassA: A_IdentifierProtocol, RawRepresentable, Equatable {...}
class MyClassB: B_IdentifierProtocol, RawRepresentable, Equatable {...}

But not even this is perfect and does not full cover your requirements.


Bottomline is that you cannot achieve exactly what you want with Swift 3.

Community
  • 1
  • 1
Lukas Kukacka
  • 7,604
  • 2
  • 25
  • 50
  • I just want to combine many methods into one. And I used generic for the base type. Which was to define associatedType – EvGeniy Ilyin Mar 22 '17 at 14:12
  • Take a look, I have added another approach, but still not exactly what you want. AFAIK you cannot achieve exactly what you want with Swift 3. – Lukas Kukacka Mar 22 '17 at 15:04