On Jan 29, 2017, at 4:01 PM, David Hart <david@hartbit.com> wrote:
On 29 Jan 2017, at 18:30, Matthew Johnson <matthew@anandabits.com> wrote:
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.
My answer depends on whether we adopt the perspective of intersection
types and allow things like `Base1 & Base2` or not. If we’re not going to
do that (at least not yet) I think your answers are the right ones.
However, if we decide to allow uninhabiatable existentials like`Base1 &
Base2` I think it would be best to just relax the rules such that they
follow the logic of intersection types.
The good news is that (as far as I can tell) it would be an additive
change to start with your rules and later adopt the intersection types
approach.
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@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-exi
stentials/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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution