[swift-evolution] Enhanced existential types proposal discussion

Austin Zheng austinzheng at gmail.com
Tue May 17 13:52:19 CDT 2016

I put together the skeleton of a proposal detailing enhancements to how
associated types can be referenced in Swift 3+. It's certainly not ready
for submission, but I think it gets across my ideas pretty well. Would love
to gather feedback and especially improvements.

Be unsparing; whatever form this feature takes will profoundly affect how
Swift developers program for years, so it needs to be done right.

See below:


An existential type is defined using the "Any<...>" construct. Existential
types can be nested.

The empty existential type "Any<>" is typealiased to 'Any'.

Within the angle brackets are zero or more 'clauses'. Clauses are separated
by semicolons. (This is so commas can be used in where constraints, below.
Better ideas are welcome. Maybe it's not necessary; we can use commas

There are five different possible clauses:

   - 'class'. Must be the first clause, if present. Places a constraint on
   the existential to be any class type. (Implies: Only one can exist.
   Mutually exclusive with class name clause.)

(In the future a follow-up proposal should add in 'struct' or 'value' as a

   - Class name. Must be the first clause, if present. (Implies: Only one
   can exist. Mutually exclusive with 'class'.) Places a constraint on the
   existential (not really an existential anymore) to be an instance of the
   class, or one of its subclasses.

Example: Any<UIViewController; UITableViewDataSource; UITableViewDelegate>
"Any UIViewController or subclass which also satisfies the table view data
source and delegate protocols"

   - Dynamic protocol. This is entirely composed of the name of a protocol
   which has no associated types or Self requirement.

Example: Any<CustomStringConvertible; BooleanType>
"Any type which conforms to both the CustomStringConvertible and
BooleanType protocols"

I'm going to use 'static protocol' to refer to a protocol with associated
types or self requirements. Feel free to propose a more sound name.

   - Self-contained static protocol, simple. This is composed of the name
   of a static protocol, optionally followed by a 'where' clause in which the
   associated types can be constrained (with any of the three basic
   conformance types: subclassing, protocol conformance, or type equality).
   Associated types are referred to with a leading dot.

Example: Any<Collection where .Generator.Element : NSObject,
.Generator.Element : SomeProtocol>
"Any type that is a Collection, whose elements are NSObjects or their
subclasses conforming to SomeProtocol."

   - Bound static protocol. This is the same as a self-contained static
   protocol, but with a leading "<name> as " which binds the protocol to a
   generic typealias. The name can be then be used in subsequent clauses to
   build constraints.

Example: Any<T as Collection; IntegerLiteralConvertible where
.IntegerLiteralType == T.Element>.
"Any type that is a Collection, and also can be built from an integer
literal, in which the collection elements are the same type as the type of
the integer used for the integer literal conformance."

There will be rules to prevent recursive nesting. For example, if generic
typealiases are allowed, they cannot refer to each other in a circular
manner (like how structs can't contain themeselves, and you can't create a
cyclic graph of enums containing themselves).

How an existential can be used depends on what guarantees are provided by
the clauses. For example, 'Any<Equatable>' can't be used for much; if there
were any methods on Equatable that did not use the associated types at all
you'd be able to call them, but that's about it. However, 'Any<Equatable
where .Self == String>' would allow for == to be called on instances. (This
is a stupid example, since Any<Equatable where .Self == String> is
equivalent to 'String', but there are almost certainly useful examples one
could come up with.)

In order of increasing 'power':

   - Don't constrain any associated types. You can pass around
   Any<Equatable>s, but that's about it.
   - Constrain associated types to conform to protocols.
   - Fully constrain associated types.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160517/3f9580fd/attachment.html>

More information about the swift-evolution mailing list