Can you create a Set of a single protocol?

I'm wondering, is it even possible to create a `Set` in Swift whose members are guaranteed only to share conformance to a Protocol?


My initial attempt looked like this:

protocol MyProtocol {}
var mySet: Set<MyProtocol> = []

But that yields the compiler error "Type 'MyProtocol' does not conform to protocol 'Hashable'".


Next I tried:

protocol MyProtocol: Hashable { }
var mySet: Set<MyProtocol> = []

But now we get the error "Protocol 'MyProtocol' can only be used as a generic constraint because it has Self or associated type requirements"

Clearly we've hit a problem with the Swift distinction between static and dynamic protocols that prevents us from using a Hashable protocol as a type parameter (because Hashable is Equatable, and Equatable for some reason requires that you're trying to equate a class to itself).


What if we try adding Hashable compliance to MyProtocol via an extension?

protocol MyProtocol {}
extension MyProtocol: Hashable {}

"Extension of protocol 'MyProtocol' cannot have an inheritance clause" - Ok, so protocol extensions cannot add protocol conformance like class extensions can.


Ok, how about we try to add conformance via a protocol extension to Hashable?

protocol MyProtocol {}
extension Hashable where Self: MyProtocol {
    var hashValue: Int { get { return 0 } } // TODO: An actual implementation
}
var mySet: Set<MyProtocol> = []

"Type 'MyProtocol' does not conform to protocol 'Hashable'" - Ok, we can't add protocol conformance like that

Protocol composition as part of the Set type parameter?

protocol MyProtocol {}
var mySet: Set<protocol<MyProtocol, Hashable>> = []

"Protocol 'Hashable' can only be used as a generic constraint because it has Self or associated type requirements" - here we are again


The one thing that does seem to work is:

protocol MyProtocol, Hashable {}
func getMySet<T: MyProtocol> -> Set<T> {
    return []
}

But now we have the problem that when we create our Set we need to provide a class (because, again, we can't use a protocol that extends MyProtocol as our T parameter because you can't use any protocol that inherits from MyProtocol as a type parameter) that all the members of our Set are guaranteed to extend.


This is severely limiting to the power of Protocols because now I cannot, for example, construct a set of all UserLike objects without knowing a single class (assuming there even is one) that all UserLike objects will also subclass. Is there a way to accomplish this without requiring that all members of my Set extend a given class?

In a simple version, any two objects which are not the same class could just return false and if they were the same class could do something like the current Equatable method.


But sometimes two values that are semantically equal are not the same type:


let myInt = 2
let myDouble = 2.0
myInt == myDouble


Maybe you could special-case numeric types, but sooner or later somebody would make the same mistake with different types. It might be 2 and "2", or it might be a String and an NSAttributedString, or it might be a Product and a ProductID. But whatever it was, somebody would write some code they expected to work, and then they'd be surprised when it didn't.


Swift is designed to prevent these kinds of problems. So Swift's designers recognized that, actually, there's something a little funny about comparing two values of different types. Iftwo values can never be equal, why are you testing whether they're equal or not? That doesn't really smell right; you're probably doing something wrong. Let's just make the compiler flag that before your code even runs so you don't make a mistake. If you really do want to compare myInt to myDouble, you'll just add the conversion. And if you don't, well, that's one less bug for you to track down when it's too late to save some poor customer's data.

Yes, there are consequences. Code using protocols as types tends to be less optimizable than code using protocols as generic constraints, and for the vast majority of Equatable types there's would be a down-casting burden for programmers (see Protocol Oriented Programming in Swift). When you want heterogeneous comparison among class instances, you can always define a superclass that is Equatable.


The fundamental reason that a protocol with Self requirements can't be used as a type is that the type P could not conform to the protocol P, a situation whose absurdity seems to outweigh its usefulness.

You are perfectly right. That's exactly why Set structures containing protocols would be very useful !!

It seems it can't be done (yet?) because as far as I understand the compiler won't check that a protocol conforms to another one : in the case of Set structures, the compiler would need to check that Element conforms to Hashable, which it will do only if Element is a concrete type.

Can you create a Set of a single protocol?
 
 
Q