Hello All!
Swift protocols serve two roles: they define requirements that conforming types implement, and they act as types in their own right (any P). But there's a gap in what you can express about the protocol itself as opposed to the types that conform to it.
Consider a protocol for application plugins:
protocol Plugin {
var name: String { get }
func activate()
}
You might want to track which plugins are available or provide a default search path. Today, the only option is a protocol extension:
extension Plugin {
static var searchPaths: [String] { ["/usr/lib/plugins", "~/.plugins"] }
}
But this has two problems:
searchPathsis inherited by every conforming type:MyPlugin.searchPathscompiles and returns the same paths, even though search paths are a property of the plugin system, not of any individual plugin.Plugin.searchPaths— the natural way to access it — doesn't compile at all. Static extension members can't be accessed on protocol metatypes.
extension P.Protocol solves both problems at once:
extension Plugin.Protocol {
static var searchPaths: [String] { ["/usr/lib/plugins", "~/.plugins"] }
}
Plugin.searchPaths // works
MyPlugin.searchPaths // error — not inherited
Scope
This proposal is limited to static members. Protocol metatype extension members are statically dispatched as they're provided directly by the extension, with no witness table involvement. They cannot reference Self, since there's no conforming type in scope. These members are effectively namespaced free functions with a natural home on the protocol.
Instance members on protocol metatypes are not addressed by this proposal. They are not inherently nonsensical — P.Protocol is itself a type, and values of that type could in principle have instance members — but P.Protocol is a singleton (there is exactly one value: P.self), so instance members would be functionally equivalent to static members with a different calling convention. The feature becomes significantly more interesting if it generalises to existential metatype extensions (P.Type), where different conforming types' metatypes are distinct values and instance members dispatch meaningfully.
Why .Protocol?
In Swift's type system, P.Protocol is already the type of the protocol value itself (the type of P.self), while P.Type is the existential metatype (the type of some unknown conforming type's metatype). Since we're extending the protocol itself and not conforming types, .Protocol is the semantically correct choice.
What this enables today
- Protocol-level configuration: search paths, default values, environment settings, etc that belong to the abstraction itself, not to any one implementation.
- Protocol-level utilities: registries, discovery mechanisms, factory methods, etc that are namespaced on the protocol they serve, rather than floating as free functions or hidden in
enumnamespaces. - Cleaner API design: library authors can attach metadata to their protocols without polluting the member namespace of every conforming type. Users see exactly what belongs to the protocol and what belongs to their type.
The full proposal text is available here which also links an initial implementation.
Saleem