Splitting this off from SE-0335: Introduce existential `any` to keep original thread focused on the review.
Proposal SE-0335 " Introduce existential any " in order to avoid redundancy in spelling of any Any suggests special treatment of protocols Any and AnyObject allowing them to be used as existential types without the any keyword. This introduces inconsistency into the language and makes it unclear if Any and AnyObject are protocols or existentials.
I'd like to investigate if it is possible to avoid this redundancy, while maintaining consistent behaviour for all protocols in the language.
If all protocols need any to be used as type, and Any does not need it, then Any must be an existential type. But according to the discussion in SE-0335: Introduce existential `any` there is demand for Any as protocol as well.
One of the ideas suggested in the original thread was to name it Value, with some concerns that this identifier will frequently shadowed, and require disambiguation as Swift.Value.
Any as protocol is rarely used, and while it needs to exist, its spelling does not need to be the most convenient one. This allows to consider some exotic alternatives for naming the null protocol - like resurrecting non-nominal spelling protocol <> or using non-ASCII identifier like π (for universal set).
But existential for arbitrary metatype is used pretty often and any (protocol <>).Type does not look very readable. So this approach would need to be complimented with AnyType for convenience.
Also, I've been thinking about AnyType, and realised that if we cannot spell Any as protocol, then AnyType is still not enough - we would also need AnyTypeType, AnyTypeTypeType, and so on. Looks like having Type as a protocol would work then - you could spell any Type, any Type.Type, etc.
If we can spell Any as protocol, but spelling is ugly, then technically we can use AnyType as a convenience for any (protocol <>).Type, while any (protocol <>).Type.Type would need to be spelled as is. This creates new inconsistency. It will affect only a tiny fraction of users, but it is still an inconsistency. So probably any Type is still a better idea than AnyType.
But there is a difference between "type being a metatype" and "type conforming to protocol Type". If we make Type a true protocol and make all metatypes conform to it, then "type being a metatype" implies that "type conforms to Type", but the reverse is not necessarily true. Regular protocols can be adopted by somethings else. So for the idea of Type to work, the Type protocol would have to be special, to be more of a notation for denoting metatypes, then an actual protocol. Making Type a protocol alias for Value.Type/(protocol <>).Type would express well what Type is.
@hborla mentioned that this was not planned to work. Is this a good enough reason to reconsider and at least enable making aliases to P.Type?
// in stdlib:
typealias Type = Value.Type
// in user code
struct S: Type {} // error: types cannot explicit declare conformance to metatype constraint
func f<T: Type>(_ x: T) // error: metatype constraint cannot be used as generic constraint
To summarise the options:
Based on Value:
| Old | Canonical | Typealias for Any | Typealias for Any and AnyType
|
Typealias for Any and Type
|
|---|---|---|---|---|
| Any as type | any Value | Any | Any | Any |
| Any as constraint | Value | Value | Value | Value |
| Any.Type | any Value.Type | any Value.Type | AnyType | any Type |
| Any.Protocol | (any Value).Type | Any.Type | Any.Type | Any.Type |
| Any.Type.Type | any Value.Type.Type | any Value.Type.Type | any Value.Type.Type | any Type.Type |
| Any.Type.Protocol | (any Value.Type).Type | (any Value.Type).Type | AnyType.Type | (any Type).Type |
Based on protocol <>:
| Old | Canonical | Typealias for Any | Typealias for Any and AnyType
|
Typealias for Any and Type
|
|---|---|---|---|---|
| Any as type | any protocol <> | Any | Any | Any |
| Any as constraint | protocol <> | protocol <> | protocol <> | protocol <> |
| Any.Type | any (protocol <>).Type | any (protocol <>).Type | AnyType | any Type |
| Any.Protocol | (any protocol <>).Type | Any.Type | Any.Type | Any.Type |
| Any.Type.Type | any (protocol <>).Type.Type | any any (protocol <>).Type.Type | any any (protocol <>).Type.Type | any Type.Type |
| Any.Type.Protocol | (any (protocol <>).Type).Type | (any (protocol <>).Type).Type | AnyType.Type | (any Type).Type |