How to do nullable generic List correctly?

Hi I am trying to write a generic function taking an optional list of types as argument like the following:

// Kotlin
fun <T: Throwable> callWithRetry(onError: List<T>?,
                                 onAnother: List<T>?) {
    onError?.forEach { println(it) }
    onAnother?.forEach { println(it) }

However, whenever I am trying to call this function with both null parameters, it would complain Not enough information to infer type variable T to me.

   callWithRetry(onError = null, onAnother = null) // `Not enough information to infer type variable T`

The workaround I can find is to pass a empty list with actual type something like:

callWithRetry(onError = null, onAnother = emptyList<RuntimeException>())

But I feels like this is just ugly and probably wrong.

Doing the same thing in TypeScript would be fine:

// TypeScript
function callWithRetry<T, R>(onError?: Array<T>, onThrow?: Array<R>): boolean {
    return false;

callWithRetry(null, null)

So my questions are:

  1. Am I doing the right thing in terms of defining nullable generic list?
  2. If this is not possible Kotlin, how could I approach this problem?

Thanks a lot!

Well, it’s true that there is not enough information in the call to infer the type T. It’s also not necessary to infer it, though, since it makes no difference. It would be nice if this was not an error.

In any case, you can make the call like this: callWithRetry<Throwable>(null, null)

You may want to add a no-argument overload that can be used instead.

OR, you can make your function non-generic, like this:

fun callWithRetry(onError: List<Throwable>?,
                  onAnother: List<Throwable>?) {
    onError?.forEach { println(it) }
    onAnother?.forEach { println(it) }

The List<T> interface is actually List<out T>, and that out means that List<U> is a List<T> if a U is a T, so you can still do this, for example:

callWithRetry(listOf(RuntimeException("asdf")), null)
1 Like

Actually I think you are right, there is no need to use generic for this now. List<Throwable> is quite suffice for now.

There is a youtracke issue about this: