Reputation: 9168
I'm implementing a class which needs to conform to a protocol that looks like this:
protocol P {
func magic<T>(_ thing: Thing, as type: T.Type) -> T
}
This protocol is provided by third-party code, which means I can't change it in any way in order to solve this problem.
Now, I have a generic function
func magicForObject<T: AnyObject>(_ thing: Thing, as type: T.Type) -> T
and I want to call it from within my implementation of magic
, just for input thing
s which are in fact objects.
That is, I want to do something like this:
func magic<T>(_ thing: Thing, as type: T.Type) -> T {
if T.self is AnyClass {
return magicForObject(thing, as: type)
}
else {
// do something else
}
}
but I can't find any way to make this work. The code above obviously doesn't compile, and neither does stuff like
if let T_ = T.self as? AnyClass { ... }
because T_
is just a normal variable, not a generic parameter (which is presumably compile-time).
I also tried doing this:
func magic<T: AnyObject>(_ thing: Thing, as type: T.Type) -> T { ... }
func magic<T>(_ thing: Thing, as type: T.Type) -> T { ... }
and implementing the two separately. The constrained AnyObject
one is correctly called if calling this function directly on the object, but not when the object is cast to protocol type P
, in which case the second one is always used.
This situation seems hopelessly constrained, but are there any workarounds I haven't thought of?
It looks like this isn't currently possible in Swift. I've made a post pitching the idea in the Swift forums; please feel free to chime in if this is something you also need.
Upvotes: 1
Views: 93
Reputation: 684
Your example is kind of hard to work with, so I had to do a lot of assumptions, but I guess this should do it for what you are requiring.
From what you said you have a given protocol P:
protocol P {
func magic<T>(_ thing: Thing, as type: T.Type) -> T
}
Lets give P a default implementation of what you need it to do:
extension P {
// Implementation for magic where T is a class
func magic<T>(_ thing: Thing, as type: T.Type) -> T where T: AnyObject {
print("AnyObject Called")
return Test2() as! T
}
// Implementation for magic where T is a struct
func magic<T>(_ thing: Thing, as type: T.Type) -> T {
print("Struct Called")
return Test() as! T
}
}
You have a class that will conform to P
class Test2: P {
}
Lets assume you have this Thing object and a struct we want to pass to see if we have the right results:
class Thing {
}
struct Test {
}
Now lets test if we call magic
on Test2
if it will call the right function accordingly to what type
is passed to magic
let test = Test()
let test2 = Test2()
// T is Test2 so its a class
test2.magic(Thing(), as: Test2.self)
// T is Test so its a struct
test2.magic(Thing(), as: Test.self)
The Print Output calls
AnyObject Called
Struct Called
which seems like you could do something for structs
and another thing for classes
Upvotes: 1