The direction I have in mind is based on introducing existential for generic types (i.e. any Array
). Here's a sketch of the space of extensions I envision as possible. We may not necessarily want to support everything I describe here, but it presents a holistic vision of what the type system might look like if we lifted as many limitations as possible.
// extends existential and conforming types
//
// does not support protocol conformances (because it extends conforming types)
// does not support nested types or protocols (because it extends conforming types)
extension Protocol {}
// extends the metatypes of existential and confoming types
//
// does not support protocol conformances (because it extends conforming types)
// does not support nested types or protocols (because it extends conforming types)
extension Protocol.Type {}
// extends the protocol existential only
//
// supports protocol conformances
// supports nested types and protocols - i.e. Protocol.HelperType
extension any Protocol {}
// extends the protocol existential metatype only
// note: there is no distinction between static and instance members here, metatypes are their own metatype
// this should be recognized by the language when validating protocol conformances
//
// supports protocol conformances
// supports nested types and protocols - i.e. Protocol.Type.HelperType
extension any Protocol.Type {}
// extends conforming types only (including `any Protocol` if it conforms)
//
// i.e. when `any Protocol: Protocol` then `extension Protocol` and `extension some Protocol` are equivalent
// does not support protocol conformances (because it extends conforming types)
// does not support nested types or protocols (because it extends conforming types)
extension some Protocol {}
// extends metatypes of conforming types only (including `any Protocol` if it conforms)
// i.e. when `any Protocol: Protocol` then `extension Protocol.Type` and `extension some Protocol.Type` are equivalent
//
// does not support protocol conformances (because it extends conforming types)
// does not support nested types or protocols (because it extends conforming types)
extension some Protocol.Type {}
// extends the protocol metatype itself
// note: there is no distinction between static and instance members here, metatypes are their own metatype
// this should be recognized by the language when validating protocol conformances
//
// supports protocol conformances and nested types
// may not reference `Self` or associated types
extension Protocol.Protocol {}
// extends concrete `Array` types as well a hypothetical `any Array` existential
//
// as today, supports protocol conformances and nested types
// if it supports nested protocols in generic types, there would be an implied associated type
// which is implicitly bound in any uses of the protocol in the implementation of this type
extension Array {}
// extends the hypothetical `any Array` existential
//
// supports protocol conformances
// supports nested types and protocols (i.e. Array.HelperType, etc)
// note: because this is extending an existential it does not have a generic context,
// therefore allowing `Array` to be used directly as a namespace for nested types, protocols, etc
//
// note: this syntax could be supported for non-generic types, but the "existenital" would be equivalent to Self
extension any Array {}
// extends the Array metatype
// note: there is no distinction between static and instance members here, metatypes are their own metatype
// this should be recognized by the language when validating protocol conformances
//
// supports protocol conformances and nested types
//
// if it supports nested protocols in generic metatypes, there would be an implied associated type
// which is implicitly bound in any uses of the protocol in the implementation of this type
//
// note: static requirements may be fulfilled by static members in the type declaration or
// extensions of the concrete type
// note: all members of a metatype extension may fulfill static protocol requirements for
// underlying concrete type conformances
extension Array.Type {}
// extends the metatype of the `any Array` existential
// note: there is no distinction between static and instance members here, metatypes are their own metatype
// this should be recognized by the language when validating protocol conformances
//
// supports protocol conformances of the `any Array` existential metatype
// suppoerts nested types and protocols (i.e. Array.Type.HelperType)
//
// note: this syntax could be supported for non-generic types, but the "existenital" would be equivalent to Self.Type
extension any Array.Type {}
With the ability for metatypes to conform to protocols, we would also be able to constrain them:
func foo<T>() where T.Type: MyProtocol
One interesting thing about this approach is that it is possible to view every type having an associated existential:
- In the trivial case, an existential is itself an existential
- Protocol metatypes are associated with the existential of the protocol they define
- Generic types and metatypes now have an associated existential that erases their type arguments
- Non-generic concrete types and metatypes are their own "existential"
We could allow access to the associated existential in the type system just as we allow access to a type's metatype without requiring generic constraints. For example:
func foo<T>() -> T.Existential where T.Existential: MyProtocol
The associated existential provides the tag we need to improve our ability to encode higher-kinded types in Swift. There are probably other interesting use cases for it as well.