Thank you @hborla for including the discussion of Any<>
in the Alternatives Considered section.
Much e-ink has been spilled about how to interpret any T.Type
, resulting in lengthy dissections of “existential metatypes” and “generic contexts”. And resolving that discussion doesn’t alleviate the possibility of confusion in the future. To wit:
I think this is a very strong indication that any T
is not the best spelling for this feature. Any<T>
has the built-in benefit of grouping via angle brackets. It is immediately clear that and how Any<T.Type>
is distinct from Any<T>.Type
. Even if you don’t understand the nuances of metatypes, you can understand that one syntax names a type that wraps a Type
object, while the other names a Type
object that wraps an Any
. If you encounter an error “Any<>
cannot be applied to Type
objects”, you immediately know you how to fix it: move the .Type
outside the angle brackets.
Moreover, Any<T>
gives us the opportunity to eliminate the intimidating term “existential” from the programmer’s mental model. Visual Basic has a much simpler name for “existential containers”: Variant
. In Swift, Any<T>
can be the new name for “existential container”. Thus, I question the relevance of this criticism from the Alternatives Considered section:
- A generic type is something programmers can implement themselves. In reality, existential types are a built-in language feature that would be very difficult to replicate with regular Swift code.
Variant
is special in Visual Basic, and I think every Swift programmer would be willing to accept Any<T>
being special in Swift as well. Any
and AnyObject
are already very special. I honestly think if you polled even moderately experienced Swift developers, they would collectively shrug at being unable to implement their own version of Any<T>
. Like any programming language, there will be parts that it cannot implement itself; a friendly name for an intimidating type-theory concept seems a fine thing to put on the other side of that boundary.
The second criticism of the Any<T>
syntax concerns static type information:
- This syntax creates the misconception that the underlying concrete type is a generic argument to
Any
that is preserved statically in the existential type. TheP
inAny<P>
looks like an implicit type parameter with a conformance requirement, but it's not; the underlying type conforming toP
is erased at compile-time.
This seems like an implementation-centric view of the feature. Just because the type system preserves the identity of the generic arguments doesn’t make that information useful to the consumer of the generic type. In fact, it can be a hindrance in the very cases that lead developers to write their own type-erasing wrappers. With Any<P>
, the language can offer a feature that programmers have been asking for since Swift first arrived: salvation from writing their own AnyFoo
type-erasing wrappers. I suspect far fewer Swift developers have been asking for a way to tell at a glance which expressions retain concrete type arguments in their static type signature. In fact, in certain circumstances I think many would class that as a usability anti-feature.