> On Jun 16, 2016, at 9:46 AM, Thorsten Seitz via swift-evolution 
> <[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


_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to