> On May 18, 2016, at 12:12 PM, Adrian Zubarev via swift-evolution 
> <[email protected]> wrote:
> 
> Okay now I feel like we’re merging everything we came up until now :D I’d 
> love to see something like this happen to Swift, because `Any` seems to be a 
> really powerful beast one day.
> 
> One quick question: Do we really need this "This must be the first 
> requirement, if present.“?

I’m on the fence about this.  The reason it would matter is for readability.  
The counter argument to that is that you can’t rely on the first argument being 
a class to determine whether a composed Any will have a class constraint or not.

> 
> I’d say the compiler should reorder all types as it wants to. Current 
> protocol<> already doing this today.
> 
> e.g.
> 
> protocol A {}
> protocol B {}
> 
> typealias C = protocol<A, B>
> typealias D = protocol<B, A>
> 
> print(C) // prints protocol<A, B>
> print(D) // prints protocol<A, B>
> print(C.self == D.self) // prints true
> 
> Basically what I mean
> 
> Any<SomeProtocol, class, AnotherProtocol>
> 
> Any<Any<ProtocolA, ProtocolB>, UIView>
> 
> should be valid.
> 
> -- 
> Adrian Zubarev
> Sent with Airmail
> 
> Am 18. Mai 2016 bei 18:30:02, Austin Zheng via swift-evolution 
> ([email protected] <mailto:[email protected]>) schrieb:
> 
>> I made heavy revisions to my proposal to reflect all the great feedback I 
>> got from you and several other folks 
>> (https://github.com/austinzheng/swift-evolution/blob/az-existentials/proposals/XXXX-enhanced-existentials.md
>>  
>> <https://github.com/austinzheng/swift-evolution/blob/az-existentials/proposals/XXXX-enhanced-existentials.md>).
>> 
>> Here are a couple of thoughts:
>> 
>> - I used 'requirements' because that's how the grammar describes similar 
>> constructs elsewhere in Swift. Open to change, though.
>> 
>> - Having only one where clause makes complete sense. Protocol extensions and 
>> generics all use one where clause, so should this construct.
>> 
>> - The "P can be used in lieu of Any<P>" just means you can declare e.g. "x : 
>> Equatable" if you want, instead of "x : Any<Equatable>", just like you can 
>> with protocols without associated types or self requirements today.
>> 
>> - I've come to the conclusion that it's probably best to propose the 
>> proposal in the most general form, and allow any reviewers on the core team 
>> to excise parts they don't think are useful enough or are too difficult to 
>> implement. In that spirit, the 'simple Any<...>' construct is gone and Any 
>> usage is fully general.
>> 
>> - I moved discussion of typealiases back into the main protocol, like you 
>> said, because typealiases using existentials are *not* actually generic and 
>> can be done today.
>> 
>> - I added some stuff about 'narrowing' existentials at point of use using 
>> as?. This isn't part of 'opening existentials' and should fit in this 
>> proposal nicely.
>> 
>> - I want a type expert to look at the 'usage' section, but I'm reasonably 
>> sure there's not much more flexibility we can give the user. Parameter 
>> associated types can't be treated as covariant (they are almost always 
>> invariant or contravariant IIRC) and therefore they should only be 
>> accessible if fully bound. Return types can be treated as covariant; some 
>> languages do and some don't. (Swift falls into the second bucket.) I would 
>> love to be wrong, though.
>> 
>> Austin
>> 
>>> On May 18, 2016, at 8:45 AM, Matthew Johnson <[email protected] 
>>> <mailto:[email protected]>> wrote:
>>> 
>>> 
>>> 
>>> Sent from my iPad
>>> 
>>> On May 18, 2016, at 2:35 AM, Austin Zheng <[email protected] 
>>> <mailto:[email protected]>> wrote:
>>> 
>>>> I've put together a considerably more detailed draft proposal, taking into 
>>>> account as much of Matthew's feedback as I could. You can find it below:
>>>> 
>>>> https://github.com/austinzheng/swift-evolution/blob/az-existentials/proposals/XXXX-enhanced-existentials.md
>>>>  
>>>> <https://github.com/austinzheng/swift-evolution/blob/az-existentials/proposals/XXXX-enhanced-existentials.md>
>>>> 
>>>> Since there is no chance this will come up for review anytime soon, I 
>>>> expect to make significant revisions to it over the next month or so. Any 
>>>> feedback would be greatly appreciated.
>>> 
>>> Thank you for working on this!  Great progress.
>>> 
>>> Minor nit, but I think the proper word is constraint rather than 
>>> requirement here:
>>> 
>>> "Within the angle brackets < and > are zero or more requirements. 
>>> Requirements are separated by commas."
>>> 
>>> Another tweak: 
>>> 
>>> "P can be used in lieu of Any<P>, where P is a protocol with or without 
>>> associated type or self requirements."
>>> 
>>> This proposal is introducing generalized existentials.  P and Any<P> should 
>>> be interchangeable for any protocol regardless of requirements of the 
>>> protocol.  Existentials of protocols with self or associated type 
>>> requirements that do not include constraints will just expose limited 
>>> direct functionality.  It would still be possible to attempt cast them to 
>>> concrete types to recover more functionality.  In the future (after a 
>>> follow on proposal) it will also be possible to open the existential.
>>> 
>>> Thorsten pointed out that there should only be one where clause for the 
>>> whole existential.  This follows the structure of generic type and function 
>>> constraints.  It may also be worth removing the 'as' alias from this 
>>> proposal.  This could be introduced as a stand alone proposal where it 
>>> would apply to any context with generic constraints.
>>> 
>>> Another item:
>>> // NOT ALLOWED let a : Any<Any<ProtocolA, ProtocolB>>
>>> 
>>> Why is this not allowed?  It is pointless, but should be allowed and 
>>> considered identical to the flattened syntax.
>>> 
>>> On dynamic casting, I don't believe it should be restricted in the way you 
>>> have defined here.  Casting *to* an existential doesn't have anything to do 
>>> with opening an existential.  We should allow casting to any existential 
>>> type.  
>>> 
>>> On a similar note, I completely disagree with the limitation you specify 
>>> for use of Any in generic constraints precisely because of your 
>>> counterargument.  In the discussion about moving the where clause it has 
>>> been noted that sometime it is necessary to apply a lot of constraints to 
>>> get the necessary effect.  A mechanism for factoring constraints is highly 
>>> desirable and will greatly improve the readability of generic code.  
>>> Typealiases bound to Any can provide such a mechanism.  Let's not 
>>> artificially restrict the use of it.
>>> 
>>> The section regarding members of a partly constrained existential needs to 
>>> be more fleshed out.  We can't simply punt it to a future proposal.  
>>> However, I do think it is a good idea to wait until the core team has time 
>>> to participate in the discussion.
>>> 
>>> The section about defining typealias also should not be left to the future. 
>>>  It is possible to define typealias with protocol<> today and to use that 
>>> alias in a generic constraint.  Removing that capability would be a 
>>> regression.  In fact, it's utility will increase significantly with this 
>>> proposal.
>>> 
>>> In general, I don't think we need the distinction between simple and full 
>>> Any.  The whole idea of this proposal IMO should be fully generalizing 
>>> existentials.  If restrictions are necessary they should be due to 
>>> (hopefully temporary) implementation considerations.
>>> 
>>>> 
>>>> Austin
>>>> 
>>>> On Tue, May 17, 2016 at 9:52 PM, Austin Zheng <[email protected] 
>>>> <mailto:[email protected]>> wrote:
>>>> 
>>>> 
>>>> On Tue, May 17, 2016 at 1:25 PM, Matthew Johnson <[email protected] 
>>>> <mailto:[email protected]>> wrote:
>>>>>  
>>>>> 
>>>>>> 
>>>>>> Within the angle brackets are zero or more 'clauses'. Clauses are 
>>>>>> separated by semicolons. (This is so commas can be used in where 
>>>>>> constraints, below. Better ideas are welcome. Maybe it's not necessary; 
>>>>>> we can use commas exclusively.)
>>>>> 
>>>>> I’m not a fan of the semicolon idea.  I don’t see any reason for this.  
>>>>> The `where` keyword separates the protocol list from the constraints just 
>>>>> fine.  The list on either side should be able to use commas with no 
>>>>> problem (or line breaks if that proposal goes through).
>>>>> 
>>>>> 
>>>>> I'm leaning towards getting rid of the commas, but would like to write 
>>>>> out a few 'dummy' examples to see if there are any readability issues 
>>>>> that arise. 
>>>> 
>>>> Replaced with what?  Whitespace separation?  I suppose that might work for 
>>>> the protocol list but it feels inconsistent with the rest of Swift.  
>>>> Commas plus (hopefully) the alternative of newline seem like the right 
>>>> direction to me.
>>>> 
>>>> Sorry, I completely misspoke (mistyped?). I meant I want to get rid of the 
>>>> semicolons and use commas. I've come to the conclusion that there are no 
>>>> readability issues, protocol<> already uses commas, and semicolons used in 
>>>> this manner don't have a precedent anywhere else in the language.
>>>>  
>>>> 
>>>>>> 
>>>>>> There are five different possible clauses:
>>>>>> 
>>>>>> 'class'. Must be the first clause, if present. Places a constraint on 
>>>>>> the existential to be any class type. (Implies: Only one can exist. 
>>>>>> Mutually exclusive with class name clause.)
>>>>>> 
>>>>>> (In the future a follow-up proposal should add in 'struct' or 'value' as 
>>>>>> a counterpart.)
>>>>> 
>>>>> If we’re going to allow `struct` we should also allow `enum`.  `value` 
>>>>> would allow either of those.
>>>>> 
>>>>> 
>>>>> Of course. A future proposal can allow list members to discuss the exact 
>>>>> details as to how struct, value, or enum specifiers should work. 
>>>> 
>>>> Yep, agree.  Just mentioning that if we’re going to reference it we should 
>>>> not leave obvious holes in what would be considered.  :)
>>>> 
>>>> Absolutely.
>>>>  
>>>> 
>>>>>> 
>>>>>> Class name. Must be the first clause, if present. (Implies: Only one can 
>>>>>> exist. Mutually exclusive with 'class'.) Places a constraint on the 
>>>>>> existential (not really an existential anymore) to be an instance of the 
>>>>>> class, or one of its subclasses.
>>>>> It is still be an existential if it includes protocol requirements that 
>>>>> the class does not fulfill.  For example, you might have Any<UIView, 
>>>>> SomeProtocol> where UIView does not conform to SomeProtocol, but various 
>>>>> subclasses do.
>>>>> 
>>>>> 
>>>>> Fair enough. (I don't think the way things work would be affected.)
>>>>>  
>>>>> Your proposal doesn’t discuss composing Any in the way that Adrian’s did 
>>>>> like this:
>>>>> 
>>>>> typealias Foo = Any<SomeClass, SomeProtocol, OtherProtocol>
>>>>> Any<AnotherProtocol, Foo>
>>>>> 
>>>>> I didn't think it needed to be discussed. An Any<...> existential type is 
>>>>> a type 'expression' just like any other, and should be allowed to 
>>>>> participate in other Any<...>s.
>>>>>  
>>>>> 
>>>>> I like the idea of composition as it allows us to factor out constraints. 
>>>>>  If we are going to do that we should allow a class to be specified in 
>>>>> the composition as long is it is a subclass of all class requirements of 
>>>>> Any types it composes.  For example, this should be allowed:
>>>>> 
>>>>> typealias Bar = Any<SubclassOfSomeClass, Foo, AnotherProtocol>
>>>>> 
>>>>> This is still one class requirement for Bar, it just refines the class 
>>>>> requirement of Foo to be SubclassOfSomeClass rather than just SomeClass.
>>>>> 
>>>>> This is a good point. There should be clarification as to how special 
>>>>> cases of Any<...> used in another Any<...> behave. For example, like you 
>>>>> said Any<MyClass, Any<SomeSubclassOfMyClass, Protocol>> should be valid. 
>>>>> This will go into any proposal that emerges from the discussion.
>>>> 
>>>> Yes, this is why we need to discuss Any composition.  There are also cases 
>>>> of incompatible associated type constraints which need to be rejected 
>>>> (such as composing two Any’s where one has Element == String and another 
>>>> has Element == Int).
>>>> 
>>>>>  
>>>>> 
>>>>>> Example: Any<UIViewController; UITableViewDataSource; 
>>>>>> UITableViewDelegate>
>>>>>> "Any UIViewController or subclass which also satisfies the table view 
>>>>>> data source and delegate protocols"
>>>>>> Dynamic protocol. This is entirely composed of the name of a protocol 
>>>>>> which has no associated types or Self requirement.
>>>>>> Example: Any<CustomStringConvertible; BooleanType>
>>>>>> "Any type which conforms to both the CustomStringConvertible and 
>>>>>> BooleanType protocols"
>>>>>> 
>>>>>> I'm going to use 'static protocol' to refer to a protocol with 
>>>>>> associated types or self requirements. Feel free to propose a more sound 
>>>>>> name.
>>>>>> 
>>>>>> Self-contained static protocol, simple. This is composed of the name of 
>>>>>> a static protocol, optionally followed by a 'where' clause in which the 
>>>>>> associated types can be constrained (with any of the three basic 
>>>>>> conformance types: subclassing, protocol conformance, or type equality). 
>>>>>> Associated types are referred to with a leading dot.
>>>>> Please do not introduce terms “dynamic protocol” and “static protocol”.  
>>>>> We want to support existentials of protocols that have self or associated 
>>>>> type requirements.  The dynamic vs static distinction is a limitation of 
>>>>> the current implementation of Swift and doesn’t make sense for the long 
>>>>> term vision.
>>>>> 
>>>>> I'm not trying to introduce new terms, these are just placeholders. At 
>>>>> the same time "protocols with self or associated type requirements" is 
>>>>> cumbersome to work with and it would be nice for someone to come up with 
>>>>> a descriptive term of art for referring to them.
>>>> 
>>>> I agree that a better term would be useful.  In the meantime, I would 
>>>> prefer something like “trivial” and “nontrivial” protocols.
>>>> 
>>>> I've decided to just use the full name until the community comes up with 
>>>> better names. Clarity is preferable to brevity in this case.
>>>>  
>>>> 
>>>>>  
>>>>> 
>>>>>> 
>>>>>> Example: Any<Collection where .Generator.Element : NSObject, 
>>>>>> .Generator.Element : SomeProtocol>
>>>>>> "Any type that is a Collection, whose elements are NSObjects or their 
>>>>>> subclasses conforming to SomeProtocol.”
>>>>> 
>>>>> Swift does not allow disjunction of requirements.  Only conjunctions are 
>>>>> supported.  That means the correct reading is:
>>>>> 
>>>>> "Any type that is a Collection, whose elements are NSObjects and their 
>>>>> subclasses conforming to SomeProtocol.”
>>>>> 
>>>>> 
>>>>> Yes, that is what I meant. "whose elements are (NSObjects or their 
>>>>> subclasses) conforming to SomeProtocol”.
>>>> 
>>>> Ok, good.  Wasn’t quite clear to me.
>>>> 
>>>> Yes, the verbiage will need to be clearer in the future. That sentence 
>>>> could be ambiguously parsed.
>>>>  
>>>> 
>>>>>> 
>>>>>> Bound static protocol. This is the same as a self-contained static 
>>>>>> protocol, but with a leading "<name> as " which binds the protocol to a 
>>>>>> generic typealias. The name can be then be used in subsequent clauses to 
>>>>>> build constraints.
>>>>>> 
>>>>>> Example: Any<T as Collection; IntegerLiteralConvertible where 
>>>>>> .IntegerLiteralType == T.Element>.
>>>>>> "Any type that is a Collection, and also can be built from an integer 
>>>>>> literal, in which the collection elements are the same type as the type 
>>>>>> of the integer used for the integer literal conformance.”
>>>>> 
>>>>> I’m not sure about this, but if we’re going to do it it should be the 
>>>>> other way around: `Collection as T` with the alias after the name of the 
>>>>> protocol.  
>>>>> 
>>>>> 
>>>>> I like this, it flows better. "Protocol as T where Protocol.Foo == Int, 
>>>>> Protocol.Bar : Baz”.
>>>> 
>>>> Why did you introduce an alias here and then not use it?  Did you mean 
>>>> "Protocol as T where T.Foo == Int, T.Bar : Baz"
>>>> 
>>>> Another result of rushing to compose an email. Sorry!
>>>>  
>>>> 
>>>>>  
>>>>> You are also using “dot shorthand” here to refer to an associated type of 
>>>>> IntegerLiteralConvertible.  I think “dot shorthand” should be limited to 
>>>>> cases where there is only one protocol that is getting constrained.  In 
>>>>> other cases, we need to be clear about which protocol we are referring to.
>>>>> 
>>>>> I borrowed dot shorthand from the generics manifesto. But you are right, 
>>>>> it should only be allowed if there is one protocol with associated types 
>>>>> or self requirements clause in the Any<...> construction.
>>>> 
>>>> I would actually go further and limit it to one protocol period, and 
>>>> possibly even to one protocol and no type names (as types can have nested 
>>>> types and typealiases).  When we allow shorthand it should be immediately 
>>>> unambiguous what the shorthand references with no need to look at type or 
>>>> protocol declarations.
>>>> 
>>>> It might be desirable to propose the proposal with no allowance for 
>>>> shorthand, and have the dot shorthand be a smaller follow-up proposal.
>>>>  
>>>> 
>>>>>  
>>>>> 
>>>>>> 
>>>>>> There will be rules to prevent recursive nesting. For example, if 
>>>>>> generic typealiases are allowed, they cannot refer to each other in a 
>>>>>> circular manner (like how structs can't contain themeselves, and you 
>>>>>> can't create a cyclic graph of enums containing themselves).
>>>>>> 
>>>>>> How an existential can be used depends on what guarantees are provided 
>>>>>> by the clauses. For example, 'Any<Equatable>' can't be used for much; if 
>>>>>> there were any methods on Equatable that did not use the associated 
>>>>>> types at all you'd be able to call them, but that's about it. However, 
>>>>>> 'Any<Equatable where .Self == String>' would allow for == to be called 
>>>>>> on instances. (This is a stupid example, since Any<Equatable where .Self 
>>>>>> == String> is equivalent to 'String', but there are almost certainly 
>>>>>> useful examples one could come up with.)
>>>>>> 
>>>>>> In order of increasing 'power':
>>>>>> Don't constrain any associated types. You can pass around 
>>>>>> Any<Equatable>s, but that's about it.
>>>>>> Constrain associated types to conform to protocols.
>>>>>> Fully constrain associated types.
>>>>> 
>>>>> I think we need to spell out pretty clearly what members we expect to be 
>>>>> available or not available.  This section probably needs the most design 
>>>>> and elaboration.  
>>>>> 
>>>>> For example, we probably can’t access a member who uses an associated 
>>>>> type as an input unless it is constrained to a specific type.  On the 
>>>>> other hand output types probably don’t need to limit access to a member.  
>>>>> However, if the output type is Self or an associated type the visible 
>>>>> signature would have an output type which has the relevant constraints of 
>>>>> the existential applied, but no more.  In some cases this means the 
>>>>> output type would simply be Any.
>>>>> 
>>>>> Absolutely. This is vaguely what I had in mind but I wanted to get 
>>>>> something down first. Thanks for thinking through some of the 
>>>>> implications :).
>>>> 
>>>> That’s what I thought.  Just wanted to start the process of elaborating 
>>>> expectations.
>>>> 
>>>>>  
>>>>> 
>>>>> Where this really gets tricky is for compound types like functions, 
>>>>> generic types, etc.  Working out the details in these cases is pretty 
>>>>> complex.  I will defer to Doug on whether it is best to just defer those 
>>>>> cases to the future, leave them up to the implementer, or try to work out 
>>>>> all of the relevant details in the proposal (in which case we probably 
>>>>> need a type system expert to help!).
>>>>> 
>>>>> Yes, exactly! For example, can Any<...> existentials involving protocols 
>>>>> with associated types or self requirements be used within generic 
>>>>> function or type definitions? Maybe there's an argument that existential 
>>>>> types of this nature are redundant if you have access to generics (e.g. 
>>>>> defining a property on a generic type that is a Collection containing 
>>>>> Ints; you should be able to do that today). On the other hand, maybe 
>>>>> there are use cases I haven't thought of…
>>>> 
>>>> I see no reason they shouldn’t be.  They are not redundant at all.  For 
>>>> example, you may want to store instances in a heterogeneous collection.  
>>>> You need existentials to do that.
>>>> 
>>>> A simple example of what I was referring to there is something like this:
>>>> 
>>>> protocol P {
>>>>     associatedtype Foo
>>>> 
>>>>     func bar(callback: (Foo) -> ())
>>>> }
>>>> 
>>>> In other words, types in the signature of a protocol member are complex 
>>>> types that reference Self or associated types.  I think you really need a 
>>>> formal understanding of the type system to understand how to expose these 
>>>> members through a constrained existential.  We can probably understand the 
>>>> expected behavior in some of the simpler cases on a case by case basis, 
>>>> but that approach doesn’t scale at all and is arbitrary.  If they’re going 
>>>> to be supported an expert is going to need to be involved in the design.
>>>> 
>>>> Yes. I have some ideas regarding this topic.
>>>>  
>>>> 
>>>>>  
>>>>> 
>>>>> One area you didn’t touch on is “opening” the existential?  Is that out 
>>>>> of scope for this proposal?  That would be fine with me as this proposal 
>>>>> is already taking on a lot.  But if so, you should mention something 
>>>>> about future directions as it is pretty closely related to this proposal.
>>>>> 
>>>>> Yes, existential opening is explicitly separate from this (although I 
>>>>> wanted to mention it in the section where I talk about how Any<Equatable> 
>>>>> is not very useful). But you are absolutely right, this proposal should 
>>>>> discuss how it wants to interact with possible future directions.
>>>>>  
>>>>> 
>>>>> Another area you didn’t touch on is whether Any constructs (and 
>>>>> typealiases referring to them) should be usable as generic constraints.  
>>>>> I would expect this to be possible but I think we need to spell it out.
>>>>> 
>>>>> I'm hoping for community input. This is a tricky subject, and at some 
>>>>> point we'll bump into implementation limitations.
>>>> 
>>>> I don’t think it’s too tricky.  You can just unpack the constraints of the 
>>>> Any into the list of generic constraints.  Maybe I’m missing something, 
>>>> but I don’t think so.
>>>> 
>>>>>  
>>>>> 
>>>>> -Matthew
>>>> 
>>>> 
>>>> 
>> 
>> _______________________________________________
>> swift-evolution mailing list
>> [email protected] <mailto:[email protected]>
>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
> _______________________________________________
> swift-evolution mailing list
> [email protected] <mailto:[email protected]>
> https://lists.swift.org/mailman/listinfo/swift-evolution 
> <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