1

In Swift, this will give me compile error

class TestType {
}

protocol TestProtocol {
   associatedtypes T: TestType
}

class TestClass<T: TestType> {
   var x: TestProtocol<T>
}

It will give me a compiler error because TestProtocol "can only be used as a generic constraint". The correct way to do this which is much less clean (because it requires adding a generic parameter of TestProtocol everywhere when it is used)

class TestClass<T: TestProtocol> {
   var x: T
}

So my question is, why doesn't Swift allow referring to a generic protocol simply as TestProtocol<T> when T is already a typed parameter as in the above example ?

Pinch
  • 2,768
  • 3
  • 28
  • 44
  • Related: [Why can we not cast to protocol types with associated types but achieve the same effect using generics?](http://stackoverflow.com/q/41695792/2976878). There is [a section of the generics manifesto](https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#generalized-existentials) which proposes syntax like `Any` in order to talk about protocols with associated types, but it's simply just not part of the language (yet). – Hamish Feb 21 '17 at 20:22
  • 1
    What exactly are you trying to achieve? There's no need to complain about the language until it actually stops you from doing what you want to do. – BallpointBen Feb 21 '17 at 21:33
  • It of course doesn't make things impossible, but adds a bunch more generic parameter declaration which makes the code hard to read and maintain which I think not necessary. – Pinch Feb 21 '17 at 21:45

1 Answers1

0

There is a little "hack" to almost get what you want: You'll have to specify the alias in the where-clause of the template parameter list:

class TestType {
    var value:Int = 0
    func doTest() { print ("doing the test \(value)") }
}

protocol TestProtocol {
    associatedtype T: TestType

    func doProtocolForTest (t:T)
}

class TestClass<TT: TestType, TP:TestProtocol> where TP.T == TT {
    var x:TP!
}

// the following demonstrats a sample usage, without much sense
// ------------------------------------------------------------
class TestProtocolImp : TestProtocol {
    func doProtocolForTest(t: TestType) {
        print ("running test...")
        t.doTest()
    }
}

let test = TestType()
test.value = 42

let tc = TestClass<TestType, TestProtocolImp>()
tc.x = TestProtocolImp()
tc.x.doProtocolForTest(t: test)
Andreas Oetjen
  • 9,889
  • 1
  • 24
  • 34
  • 1
    This really isn't too different to OP's solution of `class TestClass { var x: T }`, you're just adding an extra generic placeholder for `T.T` – this actually isn't needed, you could just define a `typealias TT = TP.T` inside the class. – Hamish Feb 21 '17 at 21:41
  • @Hamish You mean something like `class TestClass2 { typealias TT = T.TP; var x: TestProtocol }` ? This doesn't compile, because `T` is not known in that context. The OP wanted `x` to be of type `TestProtocol`, not of type `TestType` – Andreas Oetjen Feb 22 '17 at 05:03
  • No, I meant something like `class TestClass2 { typealias TT = TP.T; var x: TP; init(x: TP) { self.x = x } }`. – Hamish Feb 22 '17 at 10:56