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 |