Michele De Pascalis
Michele De Pascalis

Reputation: 952

Implementing generic interfaces in Apple's Swift

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

Answers (2)

Renetik
Renetik

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

Grimxn
Grimxn

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

Related Questions