Reputation: 143
I'm trying to create a generic function that take a closure as a parameter. I'm having an issue though, so to isolate the problem, I've created the following code that can be run in a playground.
class BaseClass {
init(message: String) {
println("Base class says: " + message)
}
func getMyName() -> String {
return "BaseClass"
}
}
class SubClass: BaseClass {
override init(message: String) {
println("Subclass says: " + message)
super.init(message: message)
}
override func getMyName() -> String {
return "SubClass"
}
func specialAbility() {
println("only I can do this!")
}
}
func makeInstance<T: BaseClass>(callback: (T -> Void)?) {
callback?(T(message: "hello"))
}
makeInstance() {
(instance: SubClass) in
println("makeInstance1 built a " + instance.getMyName())
println("I think it is a \(_stdlib_getDemangledTypeName(instance))")
//instance.specialAbility() - uncommenting this throws EXC_BAD_ACCESS at runtime
}
makeInstance() {
(instance: BaseClass) in
println("makeInstance2 built a " + instance.getMyName())
println("I think it is a \(_stdlib_getDemangledTypeName(instance))")
}
This code produces the following output:
Base class says: hello
makeInstance1 built a BaseClass
I think it is a __lldb_expr_89.SubClass
Base class says: hello
makeInstance2 built a BaseClass
I think it is a __lldb_expr_89.BaseClass
Swift doesn't let you explicitly specify the type in the function call (e.g. makeInstance), so I'm expecting the compiler to infer it from the type of closure in the call. It seems to create a BaseClass instance every time though. The SubClass initializer is not called, and its members appear to be that of BaseClass.
I daresay this seems like a bug in Swift; if you try to access a member of SubClass in the first closure, the compiler has no problems with it, but at runtime, an exception is thrown (see my comment in the code).
Any ideas how I can work around this? If it's not clear, I would like to create a subclass of BaseClass when the closure expects one.
Upvotes: 1
Views: 284
Reputation: 1296
I actually just changed your initializers to required like this:
class BaseClass {
required init(message: String) {
println("Base class says: " + message)
}
func getMyName() -> String {
return "BaseClass"
}
}
class SubClass: BaseClass {
required init(message: String) {
println("Subclass says: " + message)
super.init(message: message)
}
...
}
and it works without any problems
Upvotes: 2