Swift generics not preserving type
This code works as expected.
class BaseClass {
required init() {} // <-- ADDED THIS
func printme() -> Void {
println("I am BaseClass")
}
}
class DerivedClass : BaseClass {
override func printme() -> Void {
println("I am DerivedClass")
}
}
class Util<T: BaseClass> {
func doSomething() {
var instance = T()
instance.printme()
}
}
var util = Util<DerivedClass>()
util.doSomething()
Code base are stolen from @GregoryHigley answer :)
Marking init() {}
as required
did the thing.
This guarantees init()
is the designated initializer of ANY derived class from BaseClass
.
Without it, one can make illegal subclass like:
class IllegalDerivedClass : BaseClass {
var name:String
init(name:String) {
self.name = name
super.init()
}
override func printme() -> Void {
println("I am DerivedClass")
}
}
var util = Util<IllegalDerivedClass>()
util.doSomething()
You know this doesn't work because IllegalDerivedClass
doesn't inherit init()
initializer.
I think, that is the reason of your problem.
Anyway, whose fault is that?
- Compiler should warn about ambiguousness.
-
Runtime should try to initialize
DerivedClass()
as specified withT
. -
Debugger should show
instance
is a instance ofBaseClass
as it actually is.
ADDED:
As of Xcode 6.1 GM 2, It seems, you need more work. (in addition to required init() {}
)
class Util<T: BaseClass> {
let theClass = T.self // store type itself to variable
func doSomething() {
var instance = theClass() // then initialize
instance.printme()
}
}
I have absolutely no idea why we need this, what's going on X(
ADDED:2014/10/18
I found this also works:
func doSomething() {
var instance = (T.self as T.Type)()
instance.printme()
}
ADDED: 2015/02/10
As of Xcode Version 6.3 (6D520o) / Swift 1.2
We no longer need (T.self as T.Type)()
hack. Just T()
works as long as T
has required init()
initializer.
class Util<T: BaseClass> {
func doSomething() {
var instance = T()
instance.printme()
}
}
I created a simplified version of your code as follows:
class BaseClass {
func printme() -> Void {
println("I am BaseClass")
}
}
class DerivedClass : BaseClass {
override func printme() -> Void {
println("I am DerivedClass")
}
}
class Util<T: BaseClass> {
func doSomething() {
var instance = T()
instance.printme()
}
}
var util = Util<DerivedClass>()
util.doSomething()
This distills the problem to its essence. One would expect util.doSomething()
to print "I am DerivedClass", but it prints "I am BaseClass" every time. This has to be a bug, because no rational type system would work in this way.
I think you should file this with Apple as a bug.