> On 29 Jan 2017, at 23:12, Xiaodi Wu <[email protected]> wrote:
> 
>> On Sun, Jan 29, 2017 at 4:01 PM, David Hart via swift-evolution 
>> <[email protected]> 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 <[email protected]> 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 & Protocol3
>> Protocol1 & Something
>> Questions
>> 
>> Should class requirements be fixed to first position? I.e., should Protocol 
>> & Base be valid and equivalent to Base & Protocol?
>> Should repetition of class requirements in the same declaration be allowed? 
>> I.e., should Base & Base be valid and equivalent to Base?
>> Should repetition of class requirements through typealias expansion be 
>> allowed? I.e., should Base & (Base & Protocol) be valid and equivalent to 
>> Base & Protocol?
>> 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?
>> 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
>> 
>> No, for the reasons stated above.
>> No, because it doesn’t make sense to repeat it in the same declaration.
>> Yes, I’m gonna start agreeing with you and think will ease typealias 
>> composition.
>> No, for the same reasons as 2.
>> 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?

Yes, it would be allowed. I'll mention this example when I write the proposals 
second draft. Thanks!

> 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 <[email protected]> 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
>>>> Authors: David Hart, Austin Zheng
>>>> Review Manager: TBD
>>>> Status: TBD
>>>> 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.
>>>> 
>>>> 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.
>>>> 
>>>> 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 before
>>>> 
>>>> let b: MyObject & Hashable
>>>> // VALID: This is the new rule which allows an object type in first 
>>>> position
>>>> 
>>>> let c: CustomStringConvertible & MyObject
>>>> // INVALID: MyObject is not allowed in second position. A fix-it should 
>>>> help transform it to:
>>>> // let c: MyObject & CustomStringConvertible
>>>> 
>>>> typealias MyObjectStringConvertible = MyObject & CustomStringConvertible
>>>> let 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 & Hashable
>>>> 
>>>> typealias MyObjectStringConvertible = MyObject & CustomStringConvertible
>>>> let 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 & CustomStringConvertible
>>>> 
>>>> let b: MyObjectSubclass & MyObject & Hashable
>>>> // This is equivalent to MyObjectSubclass & Hashable
>>>> 
>>>> typealias MyObjectStringConvertible = MyObject & CustomStringConvertible
>>>> let d: MyObject & MyObjectStringConvertible
>>>> // This is equivalent to MyObject & CustomStringConvertible
>>>> 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.
>>>> Alternatives considered
>>>> 
>>>> None.
>>>> 
>>>> Acknowledgements
>>>> 
>>>> Thanks to Austin Zheng and Matthew Johnson 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
>> [email protected]
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>> 
> 
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to