Kotlin generics for functions in parameter and return type

Viewed 332

everyone! I have some class from Java dependency:

public class MyClass {
   public MyClass copy() {
      ....
   }
   public void init() {
      ...
   }
}

And I want to write a function in my Kotlin class:

fun <T : MyClass> prepareListCopy(objects: List<T>?): List<T>? =
        objects?.map { it.copy().apply { init() } }

I want my function to accept and return List of subtypes of MyClass, but IDE shows me this error: Change return type of enclosing function 'KOtlinClass.prepareListCopy' to 'List< MyClass >?'

How can I correctly define generic in this function?

1 Answers

In the definition you provided, MyClass.copy() returns MyClass. So even when you have a subtype (say MySubClass) and you call MySubClass.copy() you will still get a MyClass, not a MySubClass.

This is why you cannot say your generic function returns a List<T>?, you have to say it returns List<MyClass>?:

fun <T : MyClass> prepareListCopy(objects: List<T>?): List<MyClass>? =
        objects?.map { it.copy().apply { init() } }

(which is exactly what the error message is telling you :D)

Now given what this function does, there is no real point in knowing the exact T anymore, you could just accept a List<MyClass> (List is covariant in its type argument in Kotlin), and the function doesn't need to be generic:

fun prepareListCopy(objects: List<MyClass>?): List<MyClass>? =
        objects?.map { it.copy().apply { init() } }

If all implementations of all subclasses of MyClass guarantee that copy() returns the same subtype as the current instance (and if the documentation of copy() imposes it by contract), then you could also make your extension reified and add a safe cast:

inline fun <reified T : MyClass> prepareListCopy(objects: List<T>?): List<T>? =
        objects?.map { it.copy().apply { init() } as T }
Related