kotlinnulloption-typekotlin-null-safety

null to listOf(), not null to listOf(value) in Kotlin in one liner?


Let f() return a nullable value.

What I want to do is that
if f() is null, get an empty list,
else if f() is not null, get a list of the single item value.

In Scala, we can do something like this:

Option(f()).toList

or more verbosely

Option(f()).map(v => List(v)).getOrElse(List.empty)

In Kotlin, there is no Option (assuming no Funktionale library), and null does not have toList() unlike (None: Option) in Scala.

We have the Elvis operator, but null will be inside the listOf() function, so it will be

listOf(f() ?: /* What can I do here? */)

What we want for null is listOf(/*no argument */), but the Elvis operator requires an argument, so listOf(f() ?: ) will result in a compile error.

At least we can do

val v = f()
if (v == null) listOf() else listOf(v)

but it is a two liner.

Is there some expression for this?

Where I will use this expression is in the class's primary constructor default argument, so if it is not a one liner, it will be enclosed in brackets, so something like this:

class A(
    val p1: List<V> = run {
        val v = f()
        if (v == null) listOf() else listOf(v)
    },
    val p2: ... = ...,
    ...)

This looks pretty ugly, isn't it?


Solution

  • EDIT

    As @Naetmul pointed out, listOfNotNull(f()) is syntactically better to what I originally posted below, and also takes a variable number of arguments, for example

    val myList = listOfNotNull(f(), g(), h())
    

    will return a list of all the results that were not null.


    I would use let here.

    val myList = f()?.let { listOf(it) } ?: emptyList()
    

    Use a ?. safe call on the return value of f(), then use let to run a code block. If f() is null, it won't run this block of code, resulting in a null value. Then we use the ?: elvis operator to fall back to an empty list.

    Here it is broken up into several lines for a better understanding

    val myValue = f()
    val myList: List<Any>
    if (myValue != null) {
        myList = listOf(myValue)
    } else {
        myList = emptyList()
    }