Frans Frans - 5 months ago 15
Swift Question

How to call a static method on a base class from a generic class<T>?

I'm trying to call a static method in a base class from a generic subclass. See simplified playground code below.

Calling the non-static 'dump' function works.
The similar static call fails. Various attempts to typecast the array also fail.

In the full production code, "ClassA" is in a 3rd-party module and can't be changed. It can be further subclassed and extended. Adding a non-static wrapper for dump(), as in the below example, works.

Does Swift offer some magical typecast to have ClassT call ClassA.dump() directly?

class ClassT<T> {

var dict=[String:T]()

func add(key:String, obj:T) {
dict[key]=obj
let arr=Array(dict.values)
dump(arr) // works
ClassA.dump(arr) // error: cannot convert value of type 'Array<T>' to expected argument type '[ClassA]'
ClassA.dump(arr as! [ClassA]) // error: cannot convert value of type 'Array<T>' to type '[ClassA]' in coercion
ClassA.dump(arr as! [AnyObject]) // error: 'AnyObject' is not a subtype of 'T'
ClassA.dump(arr as! [Any]) // error: 'Any' is not a subtype of 'T'
}

}

class ClassA {

func dump(arr:[ClassA]) {
ClassA.dump(arr)
}

static func dump(arr:[ClassA]) {
print(arr)
}
}

class ClassB:ClassA {

static let o=ClassT<ClassA>()

func test() {
ClassB.o.add("Elem1", obj:self)
}
}

Answer

You have to add a constraint to specify that T derives from ClassA.

class ClassT<T : ClassA> {

    var dict = [String:T]()

    func add(key: String, obj: T) {
        dict[key] = obj
        let arr = Array(dict.values)
        dump(arr) // works
        ClassA.dump(arr)
    }
    //...

Without it, the compiler has no way to enforce that all conforming types T will be castable to ClassA.

Comments