Reputation: 952
I have a class with a property which should have as type what in other languages would be called a generic (or template) interface. When I try to mimic this behavior in Swift I cannot get protocols to work with the idea. For example:
protocol P {
typealias T
func returnT() -> T
}
class G<T>: P {
var t: T
init(t: T) {
self.t = t
}
func returnT() -> T {
return t
}
}
class C {
var p: P<Int> // Cannot specialize non-generic type 'P'
init(instanceOfP: P<Int>) { // Cannot specialize non-generic type 'P'
p = instanceOfP
}
func usePsT() -> Int {
return p.returnT() // 'P' does not have a member named 'returnT'
}
}
Errors from the compiler are reported as comments. It seems clear to me that such a situation should not be problematic: but since Swift's protocols cannot be generics (they use this obscure typealias
syntax instead) C
has no way to know that every class that implements P
can be specialized for Int
. Is there a Swift-y way to represent this situation correctly? Or is there any known workaround so that I don't have to force or de-generalize the class structure?
Upvotes: 2
Views: 1663
Reputation: 6373
My solution is not ideal but saves me a lot of complications, still code is readable... Instead of interfaces I use base class with open empty functions. Like this:
public class CSTableControllerFilter<Row: CSTableControllerRow, Data> {
open func filter(data: [Row]) -> [Row] { data }
open func onReloadDone(in controller: CSTableController<Row, Data>) {}
}
Upvotes: 0
Reputation: 22487
The generic isn't really needed in your protocol (use Any
) - it's needed in your class G<T>
. You could do this...
protocol P {
func returnT() -> Any
}
class G<T>: P {
var t: T
init(t: T) {
self.t = t
}
func returnT() -> Any {
return t
}
}
class C {
var p: P
init(instanceOfP: P) {
p = instanceOfP
}
func usePsT() -> Any {
return p.returnT()
}
}
let gi = G<Int>(t: 7) // {t 7}
let ci = C(instanceOfP: gi) // {{t 7}}
ci.usePsT() // 7
let gs = G<String>(t: "Hello")
let cs = C(instanceOfP: gs)
cs.usePsT() // "Hello"
Upvotes: 1