Is "Protocol Inheritance" the same thing as "Protocols conforming to Protocols"

Is there a difference between Protocols conforming to Protocols and Protocol Inheritance?

I'm trying to write this:

protocol Categorizable {
    var category: Set<Category> { get set }
}

but Category doesn't conform to Hashable so I wrote this:

protocol Category: Hashable {
    static var none: Self { get }
    static func custom(_: String) -> Self
}

but I get this error:

protocol Categorizable {
    var category: Set<Category> { get set } //Value of protocol type 'Category' cannot conform to 'Hashable'; only struct/enum/class types can conform to protocols
}

But I'm confused. I'm not even trying to conform a protocol to a protocol. I'm trying to make protocol Category inherit from Hashable. Is that the same thing as conforming a protocol to a protocol? Why doesn't this protocol want to inherit?

The answer is no. Protocols cannot conform to protocols.

It may be easier to understand if existential protocol types were spelled differently from concrete types. In the last code snippet, when you write Set<Category> you are using Category as the existential type containing all the concrete types conforming to the Category protocol. Set<Element>, however, requires its Element parameter type to conform to Hashable. Since existential protocol types cannot conform to protocols, you cannot use them.

The solution is to make Category a concrete type instead of a protocol.

If there was an explicit way to refer to existential protocol types, e.g. using any Category, you would be able to explicitly add conformances. It's a design already discussed. For more info check the section Clarifying existential types in Improving the UI of generics.

2 Likes

To clarify, there are two things that look the same: the protocol Category and the existential type (also called protocol type) Category. Even though they look the same, they are actually two different things. When you use a protocol as a type, you are using the existential type. That existential type cannot conform to any protocols, even itself (i.e., Category does not conform to Category).

For more information, see the corresponding educational note for this topic.

That is not quite correct. Even if we change the spelling of existential types, it does not mean that you can conform such types to protocols; and even if we implement a feature permitting users manually to state such conformances, it does not mean that it is possible (in fact, it is impossible) to write a conformance that can correctly conform an existential type to any arbitrary protocol. For one example, see the educational note.

2 Likes

Thank you @xAlien95 and @xwu. I think I'm starting to get it. So here's what I'm learning. Let me know if any of this is wrong:

  1. protocol Category: Hashable { } is inheriting correctly as I thought. Not conforming.
  2. protocol Category { } is not the same thing as Category inside of Set<Category>
    1. protocol Category { } is the actual protocol (not the existential type, a.k.a. protocol type)
    2. But the Category in Set<Category> is not the protocol itself. It is the existential type.
      • I also read here that under the hood, "An existential type is a tuple of the underlying value and the operations we can perform on that value." Is this correct?
  3. I didn't know that protocol type (the term used in the Swift documentation) is also called existential type. Are they the exact same thing, or are they two different terms that have a lot of overlap?
  4. If both of these things are spelled the same, how can I determine which one is going to be used where?
1 Like

A protocol type is just the Swift compiler's name for an existential type. They are the same thing. You know you are using the type when you are writing the name in a place that requires a type (for instance, anywhere that you can write Int and can't write Collection--this is mostly true but there are some nuances).

3 Likes