[swift-evolution] Subclass Existentials

Xiaodi Wu xiaodi.wu at gmail.com
Sun Jan 29 15:52:00 CST 2017


On Sun, Jan 29, 2017 at 3:35 PM, Matthew Johnson <matthew at anandabits.com>
wrote:

>
> On Jan 29, 2017, at 3:24 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>
> On Sun, Jan 29, 2017 at 3:11 PM, Matthew Johnson <matthew at anandabits.com>
> wrote:
>
>>
>> On Jan 29, 2017, at 3:05 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>>
>> On Sun, Jan 29, 2017 at 2:40 PM, Matthew Johnson <matthew at anandabits.com>
>>  wrote:
>>
>>>
>>> On Jan 29, 2017, at 2:25 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>>>
>>> On Sun, Jan 29, 2017 at 2:16 PM, Matthew Johnson <matthew at anandabits.com
>>> > wrote:
>>>
>>>>
>>>> On Jan 29, 2017, at 2:01 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>>>>
>>>> On Sun, Jan 29, 2017 at 1:37 PM, Matthew Johnson <matthew at anandabits.co
>>>> m> wrote:
>>>>
>>>>>
>>>>>
>>>>> Sent from my iPad
>>>>>
>>>>> On Jan 29, 2017, at 12:58 PM, Xiaodi Wu via swift-evolution <
>>>>> swift-evolution at swift.org> 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 <austinzheng at gmail.com>
>>>>> 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 <
>>>>>> swift-evolution at swift.org> wrote:
>>>>>> >
>>>>>> > Thanks for writing this proposal David.
>>>>>> >
>>>>>> >> On Jan 29, 2017, at 10:13, Xiaodi Wu via swift-evolution <
>>>>>> swift-evolution at swift.org> 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
>>>>>> > swift-evolution at swift.org
>>>>>> > https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>>
>>>>>> _______________________________________________
>>>>> 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/8f452bc1/attachment.html>


More information about the swift-evolution mailing list