Reputation: 73295
I am struggling to understand how generics / type parameters work in Kotlin. I am working on a (fairly complex) app that is throwing some very confusing error messages during compilation. I've simplified things below to the minimum amount of code that will reproduce the error.
I have an interface and two abstract classes:
interface Player {
fun play()
}
abstract class Device <T : Player> {
abstract fun getPlayer(): T
}
abstract class DeviceFactory {
abstract fun <T : Player> create(): Device<T>
}
The problem arises when I try to create a class that implements DeviceFactory
:
class MyDeviceFactory : DeviceFactory() {
class MyPlayer : Player {
override fun play() {
println("[sound plays here]")
}
}
class MyDevice : Device<MyPlayer>() {
override fun getPlayer() = MyPlayer()
}
override fun create() = MyDevice()
}
The last line of code is where the problem arises, yielding the following error message:
Conflicting overloads: public open fun create(): MyDeviceFactory.MyDevice defined in MyDeviceFactory, public abstract fun create(): Device defined in DeviceFactory
Thinking that maybe the problem was the missing type parameter, I tried this instead:
override fun <T : Player> create() = MyDevice()
Now I have a different error message:
Return type of 'create' is not a subtype of the return type of the overridden member 'public abstract fun create(): Device defined in DeviceFactory'
This doesn't make sense — MyDevice
is a subtype of Device<T>
, right? To be sure, I tried making the return type explicit:
override fun <T : Player> create(): Device<T> = MyDevice()
No dice:
Type mismatch: inferred type is MyDeviceFactory.MyDevice but Device was expected
How can I create a class that derives from DeviceFactory
and returns an instance of MyDevice
?
Upvotes: 1
Views: 630
Reputation: 2690
You need to declare the type for DeviceFactory
on it's class:
abstract class DeviceFactory<T : Player> {
abstract fun create(): Device<T>
}
Then you can define a factory that returns a concrete Player:
class MyDeviceFactory : DeviceFactory<MyPlayer>() {
override fun create(): Device<MyPlayer> = MyDevice()
}
Upvotes: 1