Will we ever be able to use generic protocols as types?

With the addition of protocol extensions in Swift 2, the only serious problem we are having with Swift is the inability to use generic protocols as a type for variables, fields, inputs, and outputs. So having variables of type MyCollection<Int> or MyCollection<where Elem == Int> if MyCollection is a protocol.


Having read the relatevant threads and seen the ugly AnySequence/AnyGenerator hacks, I recognize that this is a known issue. However for us this is a serious problem that overshadows the many innovative features of Swift. In every language we use, we separate interface from implementation. We import and depend on public abstract interfaces / protocols / traits / types. These are implemented by private concrete classes. We can't do this in Swift because we can't depend on generic protocols. Perhaps I am missing something?


So I'm wondering, does anyone know whether there are plans for this?

You can do what you're talking about with the workaround where you add as many generic parameters to your implementing struct/class as needed:

protocol MyCollection {typealias T}
struct Struct<
    MC: MyCollection where MC.T == Int
> {
    init(_ mc: MC) {self.mc = mc}
    let mc: MC
}
struct MyCollection_Int: MyCollection {typealias T = Int}
let struct_int = Struct(MyCollection_Int())

It's not good, but is there some use case for which it is not functional?

Doesn't seem to really work very well. I added another parameter which depends on the first. Crashes the compiler (6.4/7.0)


protocol MyCollection {typealias T}


struct Struct<MC: MyCollection where MC.T == Int, C:CollectionType where C.Element == MC> {
  init(_ mc: MC) {self.mc = mc}
  let mc: MC
}

struct MyCollection_Int: MyCollection {typealias T = Int; typealias C = Array<Int> }

let struct_int = Struct(MyCollection_Int())


And, of course, there is no covariant typing, so it's not actually possible to say "C.Element : MC" and build a dependency between those generic type parameters (it'll crash the compiler again, in a different way). You can use the ":" relationship between two definitely-specified types, but not between generic ones.


So even if you do this, your generic type "MC" may still be broader than it needs to be. There will be type relationships you cannot express and so you'll need to downcast later on.

Thanks Jessy, we are using that technique as a workaround in some places. We have found it to have at least two problems:

  1. Struct cannot use a statically imported function to create an MC. Instead MC instances have to be passed into the constructor, or an MC factory has to be passed into the constructor. The problem is that MC is a subtype of MyCollection, so no statically imported libraries that return MyCollection will return MC.
  2. As you say this approach is not good. My understanding is that associated types are supposed to reduce the number of parameters, but this workaround forces clients of generic libraries to be generics containing the union of all parameters they use. This is unusable.


I've been struggling with this for weeks. I assumed I was missing something idiomatic to Swift but now I'm not sure. Collections are the base case for generics, and the presence of AnySequence and AnyGenerator in the standard library suggests to me that even the base case is not adequately supported.

This recent discussion is about the same issue (not sure how I missed it).

Will we ever be able to use generic protocols as types?
 
 
Q