> On Jun 5, 2016, at 11:27 PM, L. Mihalkovic <[email protected]> 
> wrote:
> 
> 
> 
> 
> Regards
> (From mobile)
> On Jun 6, 2016, at 1:20 AM, Douglas Gregor via swift-evolution 
> <[email protected] <mailto:[email protected]>> wrote:
> 
>> 
>>> On May 18, 2016, at 12: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.
>> 
>> This is very much Swift 4 territory, but I can’t help myself… so…
>> […]
>> I’m not a fan of the “anonymous associated types” terminology: these are 
>> associated types of a type of some runtime-defined value. The only thing 
>> “anonymous” about them is that it’s harder to spell the base type; 
>> otherwise, they’re just like associated types of a generic type parameter. 
>> Again, the generics analogy is strong here.
> 
> Isn't an 'anonymous associated type' as presented synonymous for 'an 
> existential type used in the position of associated type to another 
> existential type’?

Somewhat. I find it confusing even to talk about it as being “existential”, 
because it’s not like “x.Index” is any type at run-time: it’s a particular 
associated type for the runtime type of the existential value “x”. Thinking of 
it more like a type “T.Index”, where T is effectively a generic parameter 
describing the runtime type of “x” that cannot really be named directly, makes 
it fit into a framework I can understand.

It also happens to precisely match the implementation model we’re using for 
existentials in the compiler, so perhaps I’m biased :)

> The section on 'anonymous associated types to real type' would become 
> partially redundant with the general notion of existentials, baring a few 
> possible extra usage limitations.

That’s what I expect, yeah.

>> the latter of which is fairly important, because it gives nice syntactic 
>> sure to one of the most highly-requested features [*]. I’d suggest having 
>> that example very, very early.
>> 
>>      - Doug
>> 
>> [*] That generally comes in as “Swift should have parameterized protocols…”
> 
> I am unclear about the Metatype section. I was under the impressions that all 
> reflective knownledge of a given type was esposed via Mirrors.

The Metatype section could probably use examples—again, I think it mostly falls 
out from the analogy with generics. If the protocol has static 
methods/properties or initializers, those are operations on the metatype.

        - Doug

> 
>> 
>>> 
>>> 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]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to