[swift-evolution] Class and Subclass Existentials (Round 2)

Douglas Gregor dgregor at apple.com
Mon Feb 6 16:03:51 CST 2017

> On Feb 6, 2017, at 1:18 PM, David Hart <david at hartbit.com> wrote:
> Hello mailing-list,
> I rewrote the draft proposal concerning the class and subclass existentials. Please let me know what you think, especially concerning the class and AnyObject conundrum.

Thanks for working on this! Some comments below.

	- Doug

> Regards,
> David.
> https://github.com/hartbit/swift-evolution/blob/e6411d8a9e7924bbd8a48fc292bf08d58a8d1199/proposals/XXXX-subclass-existentials.md <https://github.com/hartbit/swift-evolution/blob/e6411d8a9e7924bbd8a48fc292bf08d58a8d1199/proposals/XXXX-subclass-existentials.md>
> Class and Subtype existentials
> Proposal: SE-XXXX <https://github.com/hartbit/swift-evolution/blob/e6411d8a9e7924bbd8a48fc292bf08d58a8d1199/proposals/XXXX-subclass-existentials.md>
> Authors: David Hart <http://github.com/hartbit/>, Austin Zheng <http://github.com/austinzheng>
> Review Manager: TBD
> Status: TBD
>  <https://github.com/hartbit/swift-evolution/blob/e6411d8a9e7924bbd8a48fc292bf08d58a8d1199/proposals/XXXX-subclass-existentials.md#introduction>Introduction
> This proposal brings more expressive power to the type system by allowing Swift to represent existentials of classes and subtypes which conform to protocols.
>  <https://github.com/hartbit/swift-evolution/blob/e6411d8a9e7924bbd8a48fc292bf08d58a8d1199/proposals/XXXX-subclass-existentials.md#motivation>Motivation
> Currently, the only existentials which can be represented in Swift are conformances to a set of protocols, using the &protocol composition syntax:
> Protocol1 & Protocol2
> On the other hand, Objective-C is capable of expressing existentials of classes and subclasses conforming to protocols with the following syntax:
> id<Protocol1, Protocol2>
> Base<Protocol>*
> We propose to provide similar expressive power to Swift, which will also improve the bridging of those types from Objective-C.
>  <https://github.com/hartbit/swift-evolution/blob/e6411d8a9e7924bbd8a48fc292bf08d58a8d1199/proposals/XXXX-subclass-existentials.md#proposed-solution>Proposed solution
> The proposal keeps the existing & syntax but allows the first element, and only the first, to be either the class keyword or of class type. The equivalent to the above Objective-C types would look like this:
> class & Protocol1 & Protocol2
> Base & Protocol
> As in Objective-C, the first line is an existential of classes which conform to Protocol1 and Protocol2, and the second line is an existential of subtypes of Base which conform to Protocol.
> Here are the new proposed rules for what is valid in a existential conjunction syntax:
>  <https://github.com/hartbit/swift-evolution/blob/e6411d8a9e7924bbd8a48fc292bf08d58a8d1199/proposals/XXXX-subclass-existentials.md#1-the-first-element-in-the-protocol-composition-syntax-can-be-the-class-keyword-to-enforce-a-class-constraint>1. The first element in the protocol composition syntax can be the class keyword to enforce a class constraint:
> protocol P {}
> struct S : P {}
> class C : P {}
> let t: P & class // Compiler error: class requirement must be in first position
> let u: class & P = S() // Compiler error: S is not of class type
> let v: class & P = C() // Compiles successfully

	let w: class = C()

intended to work? (I believe the answer is “yes”)
> 2. The first element in the protocol composition syntax can be a class type to enforce the existential to be a subtype of the class:
> protocol P {}
> struct S {}
> class C {}
> class D : P {}
> class E : C, P {}
> let t: P & C // Compiler error: subclass contraint must be in first position
> let u: S & P // Compiler error: S is not of class type
> let v: C & P = D() // Compiler error: D is not a subtype of C
> let w: C & P = E() // Compiles successfully
> 3. When a protocol composition type contains a typealias, the validity of the type is determined using the following steps:
> Expand the typealias
> Normalize the type by removing duplicate constraints and replacing less specific constraints by more specific constraints (a class constraint is less specific than a class type constraint, which is less specific than a constraint of a subclass of that class).
> Check that the type does not contain two class-type constraints

Technically, if one class is a subclass of the other, we can take the subclass. We actually already do this in generic constraints:

	class C { }
	class D: C { }

	func f<T>(_: T) where T: C, T: D { }  // same as just "where T: D”

We could be more strict with existentials, but it seems unnecessary.
>  <https://github.com/hartbit/swift-evolution/blob/e6411d8a9e7924bbd8a48fc292bf08d58a8d1199/proposals/XXXX-subclass-existentials.md#class-and-anyobject>class and AnyObject
> This proposal merges the concepts of class and AnyObject, which now have the same meaning: they represent an existential for classes. They are four solutions to this dilemna:
> Do nothing.
> Replace all uses of AnyObject by class, breaking source compatibility.
> Replace all uses of class by AnyObject, breaking source compatibility.
> Redefine AnyObject as typealias AnyObject = class.

Please pick one to propose; it improves clarify for the proposal to be specific. The others can go to “Alternatives considered”.

I suggest #4 :)

Also, I think it’s good to point out that

	extension AnyObject { }

is already banned, so making AnyObject not a protocol shouldn’t actually change what code is accepted.

> Source compatibility
> Leaving aside what is decided concerning class and AnyObject, this change will not break Swift 3 compability mode because Objective-C types will continue to be imported as before. But in Swift 4 mode, all types bridged from Objective-C which use the equivalent Objective-C existential syntax could break code which does not meet the new protocol requirements.

Can you make the “import Objective-C’s SomeClass<SomeProto> as SomeClass & SomeProto” bit its own section before “Source compatibility”? The “Source compatibility” bit is more informational and shouldn’t introduce additional parts of the proposal.

> For example, the following Objective-C code:
> @interface MyViewController
> - (void)setup:(nonnull UIViewController<UITableViewDataSource,UITableViewDelegate>*)tableViewController;
> @end
> is imported into Swift-3 mode as:
> class MyViewController {
>     func setup(tableViewController: UIViewController) {}
> }
> which allows calling the function with an invalid parameter:
> let myViewController: MyViewController()
> myViewController.setup(UIViewController())
> The previous code continues to compile but still crashs if the Objective-C code calls a method of UITableViewDataSource or UITableViewDelegate. But if this proposal is accepted and implemented as-is, the Objective-C code will be imported in Swift 4 mode as:
> class MyViewController {
>     func setup(tableViewController: UIViewController & UITableViewDataSource & UITableViewDelegate) {}
> }
> That would then cause the Swift code run in version 4 mode to fail to compile with an error which states that UIViewController does not conform to the UITableViewDataSource and UITableViewDelegate protocols.
>  <https://github.com/hartbit/swift-evolution/blob/e6411d8a9e7924bbd8a48fc292bf08d58a8d1199/proposals/XXXX-subclass-existentials.md#alternatives-considered>

	- Doug

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170206/62af04a6/attachment.html>

More information about the swift-evolution mailing list