You can see what's happening this way:
protocol MyProto {}
struct S: MyProto {}
let instance: MyProto = S()
let cls: MyProto.Type = S.self
let proto = MyProto.self
func printType<T>(_ value: T) {
print(value, T.self)
}
printType(instance) // S() MyProto
printType(cls) // S MyProto.Type
printType(proto) // MyProto MyProto.Protocol
That is, MyProto.Type
and MyProto.Protocol
are different types. One of them is the type of "types that conform to the protocol"; the other is the type of "the protocol itself". (In the language of Improving the UI of generics, the former is (any MyProto).Type
.)
Okay, they're different, but why? (Since this is annoying.) The answer is because Objective-C has a function to dynamically check protocol conformances that looks something like this:
func objc_conformsToProtocol(_ cls: AnyClass, _ proto: AnyProtocol)
(Objective-C actually just calls this type "Protocol", but I've named it "AnyProtocol" to go with "AnyClass".)
The existence of this function means that protocols themselves have to have a type, and that type is distinct from "types that conform to the protocol". That's the design for any sort of reflection that acts on protocols themselves, as opposed to the types that conform to them.