[swift-evolution] Subclass Existentials

Xiaodi Wu xiaodi.wu at gmail.com
Sun Jan 29 16:12:11 CST 2017


On Sun, Jan 29, 2017 at 4:01 PM, David Hart via swift-evolution <
swift-evolution at swift.org> wrote:

> Hi Matthew,
>
> I’ll reply to this post, because it allows me to discuss a few of the
> points in the discussion, but I’ve read the whole discussion.
>
> On 29 Jan 2017, at 18:30, Matthew Johnson <matthew at anandabits.com> wrote:
>
> Hi David,
>
> This looks like a great start.
>
> One thing we should consider is whether we tie this proposal so tightly to
> classes or whether it might be better to call these supertype constraints.
> The feature might also be useful for value types if / when Swift gets value
> subtyping.
>
>
> This makes sense, especially with the Substring : String discussions going
> on. When I rework the proposal, I’ll try to make it more general.
>
> One enhancement that might be worth considering.  Specifically, allowing
> protocols to declare a specific supertype requirement in the place where a
> `class` constraint would usually be found.  After this proposal we could
> already do something similar using a `class` constraint to define a
> protocol and a typealias to bind it to the supertype requirement.  It seems
> like allowing users to state this more directly would be a good idea.
>
>
> You lost me there. Can you give examples?
>
> As only the first element in the existential composition syntax can be a
> class type, and by extending this rule to typealias expansions, we can make
> sure that we only need to read the first element to know if it contains a
> class requirement.
>
> I think this is unnecessarily limiting in a couple of ways.  I agree that
> a class should come first if it is mentioned explicitly***.  I am less sure
> we should require this when the type is part of a typealias combined with
> other protocol requirements.
>
>
> I agree with Chris that I think it’s important to require the class be
> mentioned first when the class is mentioned explicitly. Even if we lost the
> Any<Base, Protocol> syntax, there is still enough similarity to a class’s
> inheritance/conformance clause to keep the consistency and readability.
>
> For example, one use case I remember discussing with Austin is refining
> supertype requirements.  If I have a typealias which requires a superclass
> `Base` I should be able to form an existential using that typealias that
> *refines* that requirement to some type *Derived* which is a non-final
> subtype of `Base`.  This would require syntax that allows us to put a class
> name in the first position, but also mention a typealias with a supertype
> requirement in a subsequent position.
>
>
> I’ve read the examples in the thread and I think I agree that those cases
> should be accepted. But just to make sure we are on the same page, what
> does everyone think of the validity of the following cases? For shorthand,
> I use parentheses to represent typealias expansion. For example, when I
> write:
>
> Protocol1 & (Protocol2 & Protocol3)
>
> I mean:
>
> typealias Something = Protocol2 & Protocol3Protocol1 & Something
>
> *Questions*
>
>
>    1. Should class requirements be fixed to first position? I.e., should Protocol
>    & Base be valid and equivalent to Base & Protocol?
>    2. Should repetition of class requirements in the same declaration be
>    allowed? I.e., should Base & Base be valid and equivalent to Base?
>    3. Should repetition of class requirements through typealias expansion
>    be allowed? I.e., should Base & (Base & Protocol) be valid and
>    equivalent to Base & Protocol?
>    4. Should type and sub-type requirements in the same declaration be
>    allowed? I.e., should Base & Derived or Derived & Base be valid and
>    equivalent to Derived?
>    5. Should type and sub-type requirements through typealias expansion
>    be allowed? I.e., should Base & (Derived & Protocol) or Derived &
>    (Base & Protocol) be valid and equivalent to Derived & Protocol?
>
> *My Answers*
>
>
>    1. No, for the reasons stated above.
>    2. No, because it doesn’t make sense to repeat it in the same
>    declaration.
>    3. Yes, I’m gonna start agreeing with you and think will ease
>    typealias composition.
>    4. No, for the same reasons as 2.
>    5. Yes, for the same reasons as 3.
>
> That's a _reasonable_ set of answers if you want to require Base to
precede Protocol *and* you want to ease rules for typealiases. However,
using your notation, should `(Protocol & Protocol) & (Base & Protocol)` be
allowed?

If not, your rules will have to get pretty complicated. OTOH, if so, it
seems like an awfully heavy-handed yet simultaneously ineffective
hardcoding of a style preference, since I'd be able to use `typealias Base_
= Base & Any` to circumvent the rule any time I like.


David.
>
> Matthew
>
> *** One argument against requiring a class to come first is that we could
> conceptualize `&` as a type operator with a handful of overloads.  This
> would include both lhs and rhs are “protocol only kinds” as well as
> overloads with a “protocol only kind” in either lhs or rhs and a “supertype
> kind” in the other position.  The tricky part of pulling this off would be
> including an overload where both lhs and rhs have a “supertype kind”, but
> only when the operands have a subtype / supertype relationship with each
> other.
>
> I suspect this conceptualization isn’t worth the complexity it brings, but
> it is tempting to try and view `&` as a type operator.  As long as this
> only involves a loosening of restrictions it could probably be introduced
> as an additive change down the road.
>
> On Jan 29, 2017, at 10:39 AM, David Hart <david at hartbit.com> wrote:
>
> Hello,
>
> As promised, I wrote the first draft of a proposal to add class
> requirements to the existential syntax. Please let me know what you think.
>
> https://github.com/hartbit/swift-evolution/blob/subclass-
> existentials/proposals/XXXX-subclass-existentials.md
>
> Regards,
> David.
>
> Existentials for classes conforming to protocols
>
>    - Proposal: SE-XXXX
>    <https://github.com/hartbit/swift-evolution/blob/subclass-existentials/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/tree/subclass-existentials/proposals#introduction>
> Introduction
>
> This proposal brings more expressive power to the type system by allowing
> Swift to represent existentials of classes and subclasses which conform to
> protocols.
>
> <https://github.com/hartbit/swift-evolution/tree/subclass-existentials/proposals#motivation>
> Motivation
>
> Currently, the only existentials which can be represented in Swift are
> conformances to a set of protocols, using the &syntax:
>
> let existential: Hashable & CustomStringConvertible
>
> On the other hand, Objective-C is capable of expressing existentials of
> subclasses conforming to protocols with the following syntax:
>
> UIViewController<UITableViewDataSource, UITableViewDelegate>* existential;
>
> 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/tree/subclass-existentials/proposals#proposed-solution>Proposed
> solution
>
> The proposal keeps the existing & syntax but allows the first element,
> and only the first, to be of class type. The equivalent declaration to the
> above Objective-C declaration would look like this:
>
> let existential: UIViewController & UITableViewDataSource & UITableViewDelegate
>
> As in Objective-C, this existential represents classes which have
> UIViewController in their parent inheritance hierarchy and which also
> conform to the UITableViewDataSource and UITableViewDelegate protocols.
>
> As only the first element in the existential composition syntax can be a
> class type, and by extending this rule to typealias expansions, we can make
> sure that we only need to read the first element to know if it contains a
> class requirement. As a consequence, here is a list of valid and invalid
> code and the reasons for them:
>
> let a: Hashable & CustomStringConvertible// VALID: This is still valid, as beforelet b: MyObject & Hashable// VALID: This is the new rule which allows an object type in first positionlet c: CustomStringConvertible & MyObject// INVALID: MyObject is not allowed in second position. A fix-it should help transform it to:// let c: MyObject & CustomStringConvertibletypealias MyObjectStringConvertible = MyObject & CustomStringConvertiblelet d: Hashable & MyObjectStringConvertible// INVALID: The typealias expansion means that the type of d expands to Hashable & MyObject & CustomStringConvertible, which has the class in the wrong position. A fix-it should help transform it to:// let d: MyObjectStringConvertible & Hashabletypealias MyObjectStringConvertible = MyObject & CustomStringConvertiblelet e: MyOtherObject & MyObjectStringConvertible// INVALID: The typealias expansion would allow an existential with two class requirements, which is invalid
>
> The following examples could technically be legal, but we believe we
> should keep them invalid to keep the rules simple:
>
> let a: MyObject & MyObject & CustomStringConvertible// This is equivalent to MyObject & CustomStringConvertiblelet b: MyObjectSubclass & MyObject & Hashable// This is equivalent to MyObjectSubclass & Hashabletypealias MyObjectStringConvertible = MyObject & CustomStringConvertiblelet d: MyObject & MyObjectStringConvertible// This is equivalent to MyObject & CustomStringConvertible
>
>
> <https://github.com/hartbit/swift-evolution/tree/subclass-existentials/proposals#source-compatibility>Source
> compatibility
>
> This is a source breaking change. All types bridged from Objective-C which
> use the equivalent Objective-C feature import without the protocol
> conformances in Swift 3. This change would increase the existential's
> requirement and break on code which does not meet the new protocol
> requirements. For example, the following Objective-C code:
>
> @interface MyViewController
> - (void)setup:(nonnull UIViewController<UITableViewDataSource,UITableViewDelegate>*)tableViewController;@end
>
> is imported into Swift 3 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 would have worked as long as the Objective-C code did
> not call any method of UITableViewDataSource or UITableViewDelegate. But
> if this proposal is accepted and implemented as-is, the Objective-C code
> would now be imported as:
>
> class MyViewController {
>     func setup(tableViewController: UIViewController & UITableViewDataSource & UITableViewDelegate) {}
> }
>
> That would then cause the Swift code to fail to compile with an error
> which states that UIViewController does not conform to the
> UITableViewDataSource and UITableViewDelegate protocols.
>
> It is a source-breaking change, but should have a minimal impact for the
> following reasons:
>
>    - Not many Objective-C code used the existential syntax in practice.
>    - There generated errors are a good thing because they point out
>    potential crashes which would have gone un-noticed.
>
>
> <https://github.com/hartbit/swift-evolution/tree/subclass-existentials/proposals#alternatives-considered>Alternatives
> considered
>
> None.
>
> <https://github.com/hartbit/swift-evolution/tree/subclass-existentials/proposals#acknowledgements>
> Acknowledgements
> Thanks to Austin Zheng <http://github.com/austinzheng> and Matthew Johnson
> <https://github.com/anandabits> who brought a lot of attention to
> existentials in this mailing-list and from whom most of the ideas in the
> proposal come from.
>
>
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170129/a481335f/attachment.html>


More information about the swift-evolution mailing list