In addition to what has been said, maybe an explanation from a more conceptual angle.
Protocols are not types. This sounds obvious, but there's more weight to it than what especially newcomers to Swift can see.
Part of the problem is that the syntax (still) allows protocols to be used where usually types go, e.g. when you declare a variable: var someVariable: MyProtocol
. This makes the protocol look like a type, because, well, it's used where usually you'd expect a type identifier. But, as said, a protocol isn't a type, so what type does someVariable
have then? The more modern syntax makes it clear: var someVariable: any MyProtocol
. Yes, that any MyProtocol
is a type, we call that an existential. It's basically a box to erase whatever concrete type a value you assign to this variable has.
Now, the dictionary you try to create in your example has the type [MyProtocol: MyObject]
. Generics require a concrete type to be given for their type parameters (called Key
and Value
, in this case).
However, MyProtocol
is not a type, so if all this were to work like it does for variables, the actual type of our dictionary would be [any MyProtocol: MyObject]
. So far, so good, but now we run into a problem. Dictionary
constrains the Key
type to Hashable
, meaning any type that is passed for this type parameter has to conform to Hashable
. And while the protocol MyProtocol
does refine Hashable
, that only means that any type conforming to MyProtocol
also needs to conform to Hashable
.
Alas, the type any MyProtocol
does not conform to Hashable
. In fact, it doesn't even conform to MyProtocol
.
You might think "well, but it should conform!", but that's easier said than done. How would it do that? Back when I learned about this I immediately thought "It should just defer all the protocol logic to whatever type it wraps", i.e. use the instance that's boxed in it and call methods and properties of that to satisfy its own conformance to the protocol.
However, that opens a terrible can of worms and Hashable
is a great example of this. any MyProtocol
can hold heterogenous types. What if the Hashable
implementations in this are incompatible, i.e. result in lots of has collisions? This is admittedly convoluted here, but the point is that there is no easy, "right" way to do this.
Ideally we would be able to explicitly conform any MyProtocol
to protocols (including MyProtocol
itself), but I guess at this point it's perhaps easier to just define your own type erasing helper type like @Karl mentioned.