“They’re protocols, Jim, but not as we know it.” -Spock, on associatedtype
Proposal draft here.
There are two different types of protocols in Swift and they behave completely differently. Normal protocols are like any other type, use dynamic dispatch and allow for heterogenous mixtures of different implementations (similar to objects that inherit from the same base class). On the other hand, constraint protocols (distinguished only by having an associatedtype, or even more subtle, just using Self) use static dispatch, can never be used like a type, and can only be used to restrict which real types can be used for a generic function or new concrete type. This causes endless confusion:
LINKS
swift - Can you explain/solve these 'generic constraint' compiler errors? - Stack Overflow
ios - How to use associated type protocol as argument's type to a function? - Stack Overflow
swift - Protocol can only be used as a generic constraint - Stack Overflow
generics - When to use Type Constraints in Swift? - Stack Overflow
swift - Getting around "Protocol X can only be used as a generic constraint" - Stack Overflow
swift - Using associatedtype in a delegate protocol for a generic type - Stack Overflow
swift - Can you explain/solve these 'generic constraint' compiler errors? - Stack Overflow
ios - How to use generic protocol as a variable type - Stack Overflow
Almost all of these links are caused by people either creating a protocol that inherits from Equitable or Hashable without realizing that it dramatically limits how they can use it, trying to use Equitable or Hashable as a type, or adding associated types to their protocol without understanding how they work (almost certainly because the compiler told them to, when they really just wanted a higher-kinded protocol).
Their confusion is understandable; indeed, as one poster points out:
Swift documentation says that protocols are treated like any other types, but looking at some examples, I see that 'type constraint' construct is being used instead of protocol.
And they’re right! The Swift Programming Language Guide version 4.1, section Protocols, heading Protocols as Types, contains a plain lie:
Protocols don’t actually implement any functionality themselves. Nonetheless, any protocol you create will become a fully-fledged type for use in your code.
I propose we change the above lie to a truth by renaming all protocols that cannot be used as types to “constraints”, and have them declared as such:
constraint Equatable {
static func ==(lhs: Self, rhs: Self) -> Bool
}
All of their semantics stay exactly the same. Obviously anything that inherits from a constraint is also a constraint.
This would make it immediately obvious that constraints are a different animal than protocols, dramatically reducing confusion. (Protocols, of course, can be used as constraints, but that’s hardly a reason to call them the same thing; so can any class!) It would also improve two error messages:
X can only be used as a generic constraint because it has Self or associated type requirements
could be changed to:
Constraints such as X can only be used to narrow generic type variables
and we can marginally improve the terrible message:
Protocols do not allow generic parameters; use associated types instead
to:
Protocols do not allow generic parameters; you may be able to create a constraint with an associated type instead
(“May”, here, because there are some things Swift cannot do until if/when higher kinded types are added to the language. Constraints are usually a sufficient, if kludgy, alternative.)
The horrible confusion of constraint protocols has been with Swift from the very beginning. Swift 2.2 helped replacing “typealias” with “associatedtype,” but it doesn’t solve the fundamental problem that the keyword “protocol” is the declaration for two very different constructs. This change probably still won’t totally alleviate confusion, but it will go a long way towards helping people understand the distinction. Swift is the world’s first Protocol Oriented Programming language; it’s egregious for “protocol” to mean two different things.