On Sun, Jan 29, 2017 at 3:35 PM, Matthew Johnson <[email protected]> wrote:
> > On Jan 29, 2017, at 3:24 PM, Xiaodi Wu <[email protected]> wrote: > > On Sun, Jan 29, 2017 at 3:11 PM, Matthew Johnson <[email protected]> > wrote: > >> >> On Jan 29, 2017, at 3:05 PM, Xiaodi Wu <[email protected]> wrote: >> >> On Sun, Jan 29, 2017 at 2:40 PM, Matthew Johnson <[email protected]> >> wrote: >> >>> >>> On Jan 29, 2017, at 2:25 PM, Xiaodi Wu <[email protected]> wrote: >>> >>> On Sun, Jan 29, 2017 at 2:16 PM, Matthew Johnson <[email protected] >>> > wrote: >>> >>>> >>>> On Jan 29, 2017, at 2:01 PM, Xiaodi Wu <[email protected]> wrote: >>>> >>>> On Sun, Jan 29, 2017 at 1:37 PM, Matthew Johnson <[email protected] >>>> m> wrote: >>>> >>>>> >>>>> >>>>> Sent from my iPad >>>>> >>>>> On Jan 29, 2017, at 12:58 PM, Xiaodi Wu via swift-evolution < >>>>> [email protected]> wrote: >>>>> >>>>> Cool. Another avenue of improvement here is relaxing the single-class >>>>> spelling rule for the sake of composing typealiases. >>>>> >>>>> As Matthew mentioned, if I have class Base and typealiases Foo = Base >>>>> & Protocol1 and Bar = Base & Protocol2, it'd be nice to allow Foo & Bar. >>>>> >>>>> It'd be nice to go one step further: given class Derived : Base, if I >>>>> have typealiases Foo2 = Base & Protocol1 and Bar2 = Derived & Protocol2, >>>>> then it could be permitted to write Foo2 & Bar2, since there is >>>>> effectively >>>>> only one subclass requirement (Derived). >>>>> >>>>> As I understand it, the rationale for allowing only one subclass >>>>> requirement is that Swift supports only single inheritance. Thus, two >>>>> disparate subclass requirements Base1 & Base2 would make your existential >>>>> type essentially equivalent to Never. But Base1 & Base1 & Base1 is fine >>>>> for >>>>> the type system, the implementation burden (though greater) shouldn't be >>>>> too awful, and you would measurably improve composition of typealiases. >>>>> >>>>> >>>>> Yes, this is what I was indicating in my post as well. >>>>> >>>>> Are you suggesting that Base1 & Base2 compose to a type that is >>>>> treated identically to Never do you think it should be an immediate >>>>> compiler error? I remember having some discussion about this last year >>>>> and >>>>> think somebody came up with a very interesting example of where the former >>>>> might be useful. >>>>> >>>> >>>> Last year's discussion totally eludes me for some reason. But sure, if >>>> deferring the error until runtime is actually useful then why not? In the >>>> absence of an interesting use case, though, I think it'd be nice for the >>>> compiler to warn you that Base1 & Base2 is not going to be what you want. >>>> >>>> >>>> Deferring to runtime isn’t what I mean. If you try to actually *do* >>>> anything that requires an instance of `Base1 & Based` (which you almost >>>> always would) you would still get a compile time error. >>>> >>>> I managed to dig up the example from last year’s thread and it is >>>> definitely a good one: >>>> >>>> func intersection<T, U>(ts; Set<T>, us: Set<U>) -> Set<T & U> >>>> >>>> The desire is that we are always able to produce a result set. When T >>>> & U is uninhabitable it will simply be an empty set just like Set<Never> >>>> has a single value which is the empty set. >>>> >>> >>> Currently, Set<Never> is impossible because Never is not Hashable :) >>> >>> >>> Ahh, good point. I hadn’t tried it. It can easily be made Hashable >>> with a simple extension though - this code compiles today: >>> >>> extension Never: Hashable { >>> public var hashValue: Int { return 0 } >>> } >>> public func ==(lhs: Never, rhs: Never) -> Bool { return false } >>> let s = Set<Never>() >>> >>> Since concrete types *can't* be used, this example seems like it'd be of >>> little use currently. How widely useful would it be to have an intersection >>> facility such as this when T != U even if that restriction were lifted, >>> though? Seems like the only real useful thing you can do with generic Set<T >>> & U> is based on the fact that it'd be Set<Hashable>. Other than those >>> immediate thoughts, I'll have to think harder on this. >>> >>> >>> Sure, it’s possible that this is the only interesting example and may >>> not have enough value to be worthwhile. But I found it interesting enough >>> that it stuck around in the back of my mind for 8 months! :) >>> >> >> Hmm, it had not occurred to me: instantiating a Set<Hashable> is not >> supported (and you can substitute for Hashable any protocol you want). >> Thus, for any Set<T> and Set<U> that you can actually instantiate, unless T >> and U are both classes and one inherits from the other (in which case the >> generic `intersection<X>(a: Set<X>, b: Set<X>) -> Set<X>` already >> suffices), Set<T & U> must be the empty set. This is not a very interesting >> result. >> >> >> Yes, but this is a limitation due to the fact the existentials for a >> protocol do not conform to the protocol. In some cases the existential >> *cannot* conform to the protocol but in many cases (especially common >> cases) it *can*. It just doesn’t today. There is widespread desire to see >> this situation improve. >> > > Sure, but when will be the day that existentials conform to their own > protocol when they can do so, *and* we extend `&` to value types (probably > not until they can express some sort of meaningful subtyping relationship > to each other)? > > > I hope it isn’t *too* long before existentials conform to their own > protocol at least in simple cases - Swift 5 if it doesn’t make it into > Swift 4. > I will bet you two virtual alcoholic beverages that it won't happen before Swift 7 or one that it won't happen before Swift 9. > I am suggesting this proposal be generalized such that it discusses > concrete subtype / supertype relationships rather than restricting it’s > scope to classes. If that approach is adopted then `&` would allow value > types as soon as this proposal is implemented. > > It seems arbitrary and unnecessary to restrict it to classes even if that > is where it would be most useful when it is first implemented. > One can naturally relax the rules in tandem with the design and implementation of prerequisite features that make the more relaxed rules useful. The point I'm trying to make is: there is currently no value of X for which the following statement holds true-- "If only it weren't for the restriction against writing `Base1 & Base2`, I'd be able to implement the interesting algorithm X." So it seems reasonable to error on `Base1 & Base2`. > At that point, I'd advocate for using compiler magic to make uninhabited > types like Never a subtype of all types conforming to all protocols. Then, > we could actually write Set<Never> without having to implement conformance > to Hashable by writing a bogus `==` function. And we could replace > EmptyCollection with Collection<Never> and simplify the standard library > API surface that way (since Array<Never>() would then be a value of type > Array<T>, etc.). And, your demonstrated use case would become interesting. > Since there is a pretty good chance that you and I won't be alive by then, > I'm happy to punt on the ideation process for this :) > > >> It generalizes easily to any cases where you have a generic type that is >>> useful despite not necessarily having access to instances of the >>> parameterized type. >>> >>> If we allow this, I *think* all uninhabitable types could be unified >>> semantically by making `Never` a protocol and giving them implicit >>> conformance. >>> >>> >>> This example points even more strongly in the direction of allowing >>>> *any* concrete type to be used, not just classes - even today we could >>>> produce uninhabitable existentials like this using value types. >>>> >>>> Here’s the link to the thread: https://lists.swift.or >>>> g/pipermail/swift-evolution/Week-of-Mon-20160523/019463.html >>>> >>>> >>>> >>>> On Sun, Jan 29, 2017 at 12:41 Austin Zheng <[email protected]> >>>>> wrote: >>>>> >>>>>> The "class comes first" requirement made more sense when the proposed >>>>>> syntax was still "Any<T, U, V>", intentionally mirroring how the >>>>>> superclass >>>>>> and conformances are declared on a class declaration (the archives >>>>>> contain >>>>>> more detailed arguments, both pro and con). Now that the syntax is "T & >>>>>> U & >>>>>> V", I agree that privileging the class requirement is counterintuitive >>>>>> and >>>>>> probably unhelpful. >>>>>> >>>>>> Austin >>>>>> >>>>>> > On Jan 29, 2017, at 10:37 AM, Matt Whiteside via swift-evolution < >>>>>> [email protected]> wrote: >>>>>> > >>>>>> > Thanks for writing this proposal David. >>>>>> > >>>>>> >> On Jan 29, 2017, at 10:13, Xiaodi Wu via swift-evolution < >>>>>> [email protected]> wrote: >>>>>> >> >>>>>> >> As Matthew mentioned, the rules can certainly later be relaxed, >>>>>> but given that this proposal has the compiler generating fix-its for >>>>>> subclasses in second position, is there a reason other than stylistic for >>>>>> demanding MyClass & MyProtocol instead of MyProtocol & MyClass? >>>>>> >> >>>>>> >> From a naive perspective, it seems that if the compiler >>>>>> understands my meaning perfectly, it should just accept that spelling >>>>>> rather than complain. >>>>>> > >>>>>> > I had that thought too. Since ‘and’ is a symmetric operation, >>>>>> requiring the class to be in the first position seems counter-intuitive. >>>>>> > >>>>>> > -Matt >>>>>> > >>>>>> > _______________________________________________ >>>>>> > 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 >>>>> >>>>> >> > >
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
