Reputation: 576
In Kotlin, I'm trying to compile the following:
The following code does not compile, because a type is required at:
fun getMapper(animalType: AnimalType): Printer
I tried to use <Any>
or <*>
but got no success. Can someone help?
(easy to see the error by copypasting the code below into https://try.kotlinlang.org)
enum class AnimalType {
CAT, DOG
}
class Dog
class Cat
interface Printer<in T> {
fun mapToString(input: T): String
}
class DogPrinter : Printer<Dog> {
override fun mapToString(input: Dog): String {
return "dog"
}
}
class CatPrinter : Printer<Cat> {
override fun mapToString(input: Cat): String {
return "cat"
}
}
private fun getMapper(animalType: AnimalType): Printer {
return when(animalType) {
AnimalType.CAT -> CatPrinter()
AnimalType.DOG -> DogPrinter()
}
}
fun usage_does_not_compile() {
getMapper(AnimalType.DOG)
.mapToString(5)
}
Upvotes: 7
Views: 15031
Reputation: 81929
I've modified your code a bit. The getMapper
function is inline
with a reified
generic type now, which makes the call pretty readable at getMapper<Dog>()
.
Read about reified
here: What does the reified keyword in Kotlin really do?
private inline fun <reified T> getMapper(): Printer<T> {
when (T::class) {
Cat::class -> return CatPrinter() as Printer<T>
Dog::class -> return DogPrinter() as Printer<T>
}
throw IllegalArgumentException()
}
fun main(args: Array<String>) {
println(getMapper<Dog>().mapToString(Dog()))
println(getMapper<Cat>().mapToString(Cat()))
}
The reified thing is not even necessary actually but makes the client side more readable. Alternatively, you could also pass in the class as an argument to the getMapper
function. The really important part is to make this one generic.
The unchecked casts are not very cool but seem to be safe here.
Upvotes: 6
Reputation: 170745
Returning Printer<*>
works fine. But it isn't actually useful because you can't call mapToString(Dog())
(I assume mapToString(5)
is a typo) and it's a good thing: if it compiled then
getMapper(AnimalType.CAT).mapToString(Dog())
would also have to compile, because the return type can only depend on argument type, not on value, and AnimalType.CAT
and AnimalType.DOG
have the same type. There are some languages which allow it, but Kotlin isn't one of them.
Upvotes: 0
Reputation: 4796
Kotlin doesn't have raw types so you can't return Printer
from getMapper
. You can either return Printer<*>
, make getMapper
generic, or change your inheritance structure to have a common super type.
Upvotes: 0