> 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
