Reputation: 72760
What I am trying to do is to inject a closure into a class initializer so that I can control its initialization from outside.
I've defined a protocol which must be implemented by the classes I want to initialize:
protocol EntityInitializable {
typealias T : EntityInitializable
init(initializer: (T) -> ())
}
and a function attempting to inject the closure
class EntityMapper<T : EntityInitializable> {
func f() -> T {
var cb = {(entity: T) -> () in
}
return T(cb)
}
}
This generates the following error during compilation:
error: cannot convert the expression's type 'T.T' to type 'T' return T(cb)
If I modify the above code removing the generics part, such as:
class MyClass {
init(initializer: (MyClass) -> ()) {
}
}
class EntityMapper {
func f() -> MyClass {
var cb = {(entity: MyClass) -> () in
}
return MyClass(cb)
}
}
it works.
Any idea about what's wrong? Is it perhaps because I am trying to make recursive use of generics, by creating an instance of a generic and passing a closure with a parameter of the same generic type?
Upvotes: 0
Views: 248
Reputation: 2490
The reason that your code doesn't work is that there is nothing that says the T
in
EntityInitializable (for clarity I'll call it EntityType
from here on) must be equal to the type that implements the protocol. Here's an example that should shed some light on the issue:
class A: EntityInitializable {
typealias EntityType = B
init(initializer: (EntityType) -> ()) {
}
}
class B: EntityInitializable {
// [...]
}
This is perfectly fine according to the code you wrote and it's the reason why the compiler doesn't accept the cb
closure. Its entity
parameter has type T
, while EntityInitializable
expect its type to be T.EntityType
.
The right way to write this code is by using Self
which represents the class that implements the protocol:
protocol EntityInitializable {
init(initializer: (Self) -> ())
}
Upvotes: 1