Syntax for existential type as a box for generic type

We saw the any keyword surfacing in Improving the UI of generics: Clarifying existential types as a way to explicitly refer to existentials types (should we officially call them Protocol Types from now on like the Swift Programming Language Guide does?) and having semantic connections with the some keyword used to refer to opaque types. Ideally, you would have

var a: some Collection = [1, 2]  // a concrete type
var b: any Collection = [9, 12]  // an existential type

a = [3, 4]  // error, type of a is known only at runtime
            // and differs from any Collection conforming type

b = [3, 4]  // no error, b can store any Collection

Opaque types can only be built with protocols or base classes as of Swift 5.3:

var a: some Int = 2  // error: an 'opaque' type must specify only
                     // 'Any', 'AnyObject', protocols, and/or a base class

(weirdly Any and AnyObject are explicitly mentioned in the error, although both of them are protocols, so there's a bit of redundancy here)

I suspect that the any keyword should behave the same, i.e. it should be allowed to be put before a protocol or a base class.

The syntax you are proposing differs in this regard since you would like to put any before a type instead of a protocol, thus removing any similarities between any and some.


Let us compare your proposed syntax with the current one and the imagined any syntax discussed in Improving the UI of generics:

// proposed syntax
var c: any<T> [T]
var d: any<T> [T] where T: Protocol
var d: any<T: Protocol> [T]

// current syntax
var c: [Any]
var d: [Protocol]  // if Protocol can be a protocol type (existential)

// proposed syntax in "Clarifying existential types"
var c: [any Any]
var d: [any Protocol]

If I'm correct you want to use any<...> as a collector of type parameters involved in a generic type, thus gaining the ability to refer to existential types having constrained concrete types (which are only available at runtime) in multiple places:

var e: any<T> [KeyWrapper<T>: ValueWrapper<T>]
var f: any<T> [KeyWrapper<T>: ValueWrapper<T>] where T: Protocol
var f: any<T: Protocol> [KeyWrapper<T>: ValueWrapper<T>]

This feature however can already be expressed today using a generic typealias as a mid step:

typealias MyDictionary<T> = [KeyWrapper<T>: ValueWrapper<T>]

// current syntax
var e: MyDictionary<Any>
var f: MyDictionary<Protocol>  // if Protocol can be a protocol type

// proposed syntax in "Clarifying existential types"
var e: MyDictionary<any Any>
var f: MyDictionary<any Protocol>

Here, the protocol type, although existential, is constrained to have the same concrete type at runtime in both the wrapped keys and values of the dictionary.


My question is: should we break any and some analogies in favor of this different use of the any keyword?