Would you mind clarifying this for me, perhaps with an example case? AFAIK associated types are inferred from witnesses in concrete types. Since concrete types have all members actualized, there does not appear to be any additional ambiguity introduced by supertype compatibility in member signatures.
Certainly there exist ways of re-architecting these simple examples so as to work around the issue. However, that's hardly the point of this thread – introducing associated types into a protocol fundamentally changes the requirements of this type as well as its member signatures.
protocol Animal { var head: AnimalHead { get } }
This Animal describes a promise that the concrete type should yield any kind of head, with the only requirement that it conform to AnimalHead.
protocol Animal { associatedtype Head: AnimalHead; var head: Head { get } }
This Animal describes a promise that the concrete type must expose a new concrete type of head whose minimum requirements are that it conforms to AnimalHead but additionally that it fully expose all concrete details regarding the particular head the subtype implements.
Ignoring the fact that the latter is clearly a different type of contract, far more expensive, demanding and poorly encapsulated, we also ought to acknowledge that the current implementation is counter-intuitive and surprising when we take a moment to think about the type promises involved:
protocol AnimalHead {}
protocol Animal {
var head: AnimalHead { get }
}
These protocol requirements simply say, "any Animal must have a head that conforms to AnimalHead".
The reality is that in the following example (which fails to compile):
struct HorseHead : AnimalHead {}
struct Horse: Animal {
let head = HorseHead()
}
These protocol requirements are met. The Horse type is compatible with the Animal protocol's contract.
The failure case is that the compiler is enforcing additional requirements onto subtypes, namely that in addition to "any Animal must have a head that conforms to AnimalHead", it also enforces that "Animals may not specialize their head.", and it is unclear whether this additional requirement should be a part of the way users should expect protocol types to behave.
Notably, for instance, this additional requirement is absent in classes:
class AnimalHead {}
class Animal {
var head: AnimalHead { AnimalHead()}
}
class HorseHead: AnimalHead {}
class Horse: Animal {
override var head: HorseHead { HorseHead() }
}