While this is an interesting direction I have some concerns with this pitch. It strongly feels like we would like to revert some
in almost all places and reverting several past proposals on that topic. I'm personally not in favor of such drastic change.
If you recall we want to be able to refer to a protocol as both an existential or the protocol. If that change this would not be possible.
typealias MyP = P // MyP is a protocol alias not an alias for `some P`
typealias AnyP = any P // aliasing the existential
We could also introduce the ability to have several very useful meanings in extensions when using P
, any P
and some P
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.
So it's -1 for me.
8 Likes