0

I'm having this compilation error and I don't really know what's the best way to solve it.

In this basic exemple, the error says Type 'any Leg' cannot conform to 'Leg' .

I've tried to mirror the same hierarchy that I have in my project, but I just couldn't come up with something better at the moment (it's not about dogs obviously).

protocol Animal { 
    var legs: [Leg] { get }
}

class Dog: Animal {
    var legs: [Leg] = []
}

protocol Leg {} 

protocol ZoneOfBody {} 

extension Array: ZoneOfBody where Element: Leg {}

func test() -> ZoneOfBody {
    let dog = Dog()
    return dog.legs // <---- The compilation error is here
}

What possibilities do I have ? Thanks in advance

Xys
  • 8,486
  • 2
  • 38
  • 56
  • A protocol cannot conform to a protocol. What is the code supposed to do? What is `legs` in `test` supposed to be. `Leg` and `ZoneOfBody` do nothing. It seems that you are going to abstract your code to death. At some point the type represented by a protocol must be a concrete static type. – vadian Aug 16 '23 at 14:22
  • The app has a modular architecture and most of the protocols needed here are in a shared module. The concrete implementations are in the main module though. And why do you say a protocol cannot conform to a protocol ? You can have a protocol that conforms to Equatable for example ? – Xys Aug 16 '23 at 14:25
  • I mean a protocol cannot conform to itself. – vadian Aug 16 '23 at 14:29
  • This was previously closed as a duplicate, but the answer given on the linked question was quite complex and involved and doesn't directly answer this question. So I reopened it and posted an answer that fixes this particular issue. – JeremyP Aug 16 '23 at 15:41

1 Answers1

1

Protocols cannot conform to themselves and dog.legs refers to an array of a protocol which cannot meet the requirement that the return type conform to Leg, which may seem bizarre but there are good reasons.

To fix this, the legs property of Dog must be an array of a concrete type. Also, the type in the protocol needs to be an associated type (or Dog won't conform).

The following code is what you need.

protocol Animal {
    associatedtype L: Leg // Associated type
    var legs: [L]{ get set }
}

struct DogLeg: Leg {} // Concrete type conforming to Leg

class Dog: Animal {
    var legs: [DogLeg] = [] // This now meets the protocol requirement
}

protocol Leg {}

protocol ZoneOfBody {}

extension Array: ZoneOfBody where Element: Leg {}

func test() -> ZoneOfBody {
    let dog = Dog()
    return dog.legs // Now compiles
}
JeremyP
  • 84,577
  • 15
  • 123
  • 161
  • Thank you very much for your answer ! Indeed it fixes the issue. However I'm getting a new error now : `Use of protocol 'Animal' as a type must be written 'any Animal'` everywhere this protocol is used (as a method parameter for example). And since this protocol is used almost everywhere in the app, I was wondering if there was a way to avoid this ? – Xys Aug 17 '23 at 09:47
  • @Xys that's a new diagnostic introduced in recent versions of Swift. There's no way around it except to insert `any` as stated. It was introduced because people keep confusing protocols with types. – JeremyP Aug 17 '23 at 14:14