> On Jun 19, 2016, at 8:35 AM, Douglas Gregor via swift-evolution 
> <[email protected]> wrote:
> 
> 
> 
> Sent from my iPhone
> 
> On Jun 18, 2016, at 2:29 AM, Thorsten Seitz <[email protected] 
> <mailto:[email protected]>> wrote:
> 
>> 
>>> Am 17.06.2016 um 16:11 schrieb Douglas Gregor <[email protected] 
>>> <mailto:[email protected]>>:
>>> 
>>> 
>>>> On Jun 16, 2016, at 9:46 AM, Thorsten Seitz via swift-evolution 
>>>> <[email protected] <mailto:[email protected]>> wrote:
>>>> 
>>>>> 
>>>>> Am 16.06.2016 um 17:36 schrieb Paul Cantrell <[email protected] 
>>>>> <mailto:[email protected]>>:
>>>>> 
>>>>>> On Jun 16, 2016, at 8:29 AM, Thorsten Seitz via swift-evolution 
>>>>>> <[email protected] <mailto:[email protected]>> wrote:
>>>>>> 
>>>>>> Protocols are a mechanism for deriving types from each other whereas 
>>>>>> generics are a way to parameterize types. My point was that Swift's 
>>>>>> other way to parameterize types, namely by associated types, is very 
>>>>>> similar to generics with wildcards when looking a the existentials of 
>>>>>> such protocols.
>>>>> 
>>>>> This has been a point of confusion for me as well. I keep hearing that 
>>>>> associated types are different from generic protocols, but this seems 
>>>>> like a distinction without a difference.
>>>>> 
>>>>> Suppose Swift allowed generic protocols. How would a hypothetical 
>>>>> Collection<Foo> be different in practice from the proposed existential 
>>>>> Any<Collection where .Element == Foo>?
>>>>> 
>>>>> Yes, in the realm of type theory and compiler internals they might 
>>>>> represented differently, sure. But in practice, in terms of what code can 
>>>>> actually do? I know of only two differences:
>>>>> 
>>>>> 1. A type can only conform to any given protocol with one set of type 
>>>>> parameters. (Nothing can be both Collection<Foo> and Collection<Bar>.)
>>>>> 
>>>>> 2. When a type conforms to Collection, it declares “associatedtype Foo” 
>>>>> instead of “: Collection<Foo>”, and Foo can be inferred by the compiler 
>>>>> in some circumstances. That’s handy, but it’s a syntactic difference.
>>>> 
>>>> That syntactic difference is *very* handy IMO for the following reason: 
>>>> with generics I have to repeat all types over and over again which gets 
>>>> ugly when I have levels of nesting where type parameters are constrained 
>>>> by other generics, which requires adding their parameters to the parameter 
>>>> list. Essentially the nested parameters have to be fully flattened because 
>>>> each type parameter has to be explicitly specified.
>>>> 
>>>> I’ll try to show that with a simplified example:
>>>> 
>>>> // with associated types
>>>> 
>>>> protocol Edge {
>>>>     associatedtype VertexType
>>>> 
>>>>     var source: VertexType { get }
>>>>     var target: VertexType { get }
>>>> }
>>>> 
>>>> protocol Graph {
>>>>     associatedtype EdgeType : Edge
>>>>     
>>>>     var vertices: [EdgeType.VertexType] { get }
>>>>     var edges: [EdgeType] { get }
>>>>     
>>>>     func outEdges(vertex: EdgeType.VertexType) -> [EdgeType]
>>>> }
>>>> 
>>>> protocol GraphIterator {
>>>>     associatedtype GraphType : Graph
>>>>     
>>>>     var graph: GraphType { get }
>>>>     
>>>>     var startVertex: GraphType.VertexType { get }
>>>>     
>>>>     func enter(vertex: GraphType.VertexType)
>>>>     func propagate(along edge: GraphType.EdgeType)
>>>>     func finish(vertex: GraphType.VertexType)
>>>> }
>>>> 
>>>> 
>>>> // with generics
>>>> 
>>>> class Edge<VertexType> {
>>>>     var source: VertexType
>>>>     var target: VertexType
>>>> }
>>>> 
>>>> class Graph<VertexType, EdgeType: Edge<VertexType>> {
>>>>     
>>>>     var vertices: [VertexType]
>>>>     var edges: [EdgeType]
>>>>     
>>>>     func outEdges(vertex: VertexType) -> [EdgeType]
>>>>     
>>>> }
>>>> 
>>>> class GraphIterator<VertexType, EdgeType: Edge<VertexType>, GraphType: 
>>>> Graph<VertexType, EdgeType>> {
>>>>     
>>>>     var graph: GraphType
>>>>     
>>>>     var startVertex: VertexType
>>>>     
>>>>     func enter(vertex: VertexType)
>>>>     func propagate(along edge: EdgeType)
>>>>     func finish(vertex: VertexType)
>>>> }
>>>> 
>>>> Note, how the parameter list for GraphIterator exploded, because I had to 
>>>> list each level of nested types down to the VertexType, whereas
>>>> in the associated types example the GraphIterator simply declares an 
>>>> associated type conforming to the topmost type of my nesting, the Graph.
>>>> 
>>>> 
>>>>> 
>>>>> Is there a deeper difference I’m missing?
>>>> 
>>>> Maybe Dave can chime in here?
>>> 
>>> You can recover an associated type (say, X.Element) by just having the type 
>>> “X”, but this is not true for a type parameter. That doesn’t matter when 
>>> you have (or want to specify) that type… for example, your comment that 
>>> Collection<Foo> and Any<Collection where .Element == Foo> would basically 
>>> be the same thing.
>>> 
>>> However, with generalized/enhanced existentials you would be able to write
>>> 
>>>     var heterogeneousArrayOfCollections: [Collection]
>>>     heterogeneousArrayOfCollections.append([1, 2 3])
>>>     heterogeneousArrayOfCollections.append([“Hello” : 1, “Swift” : 2])
>>> 
>>> You can’t do that with generic protocols, because there is no common 
>>> element type:
>>> 
>>>     var heterogeneousArrayOfCollections: [Collection<???>]
>>> 
>>> One could perhaps try to rely on subtyping of collections for this specific 
>>> case
>>> 
>>>     var heterogeneousArrayOfCollections: [Collection<Any>]
>>>     heterogeneousArrayOfCollections.append([1, 2 3])
>>>     heterogeneousArrayOfCollections.append([“Hello” : 1, “Swift” : 2])
>>> 
>>> but that’s not something we have now and doesn’t really generalize well in 
>>> Swift.
>>> 
>>> - Doug
>>> 
>>> 
>> 
>> Wildcards would work, too, e.g. in Java it looks like follows:
>> List<Collection<?>> heterogeneousListOfCollections = new ArrayList<>();
>> 
>> List<Integer> intList = new ArrayList<>();
>> Collections.addAll(intList, 1, 2, 3);
>> 
>> List<String> stringList = new ArrayList<>();
>> Collections.addAll(stringList, "Hello", "Swift");
>> 
>> heterogeneousListOfCollections.add(intList);
>> heterogeneousListOfCollections.add(stringList);
> 
> Having to add wildcards means yet another advanced generics feature. I 
> suspect that we can make generalized existentials sufficiently accessible for 
> all Swift programmers. Not so sure one could do that with generic protocols 
> and wildcards (Java's experience with wildcards is not encouraging).

maybe : 
var heterogeneousListOfCollections: [Collection[Any]] 

(per https://gist.github.com/lmihalkovic/68c321ea7ffe27e553e37b794309b051)

> _______________________________________________
> 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