Improving the UI of generics

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.