I\'m trying cast and/or generate a variable based upon the specified generic type. I understand there is no type erasure in swift, but it doesn\'t seem like the generics pre
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?
DerivedClass()
as specified with T
.instance
is a instance of BaseClass
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()
}
}
The problem is var instance = T()
Initialisers are not virtual so the instance is always made with BaseClass()
*. The following code uses a class function to work around the problem:
class BaseClass {
func printme() -> String {
return "I am BaseClass"
}
class func makeInstance() -> BaseClass
{
return BaseClass()
}
}
class DerivedClass : BaseClass {
override class func makeInstance() -> BaseClass
{
return DerivedClass()
}
override func printme() -> String {
return "I am DerivedClass"
}
}
class Util<T: BaseClass> {
func doSomething() -> String {
var instance = T.makeInstance()
return instance.printme()
}
}
var util = Util<DerivedClass>()
println("\(util.doSomething())")
I changed the implementation of printme()
only because the original code didn't print anything in a playground for some reason.
* I think this is still a bug.
I had a similar issue. You need to add required
initializer and let realType = T.self
and replace T()
with realType()
.
class BaseClass {
required init() {}
func printme() -> Void {
println("I am BaseClass")
}
}
class DerivedClass : BaseClass {
override func printme() -> Void {
println("I am DerivedClass")
}
}
class Util<T: BaseClass> {
func doSomething() {
let realType = T.self // that's it
var instance = realType()
instance.printme()
}
}
var util = Util<DerivedClass>()
util.doSomething()
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.