Is there a way to use the default value on a non-optional parameter when null is passed?

Bryan picture Bryan · Jun 23, 2017 · Viewed 26.8k times · Source

For example, if I have the following data class:

data class Data(
    val name: String = "",
    val number: Long = 0
)

And functions that can return null:

fun newName(): String? {}

fun newNumber(): Long? {}

I know I can use the following to use the value of the functions if they are not null:

val newName = newName()
val newNumber = newNumber()

val data = Data(
        if (newName != null) newName else "",
        if (newNumber != null) newNumber else 0
)

But is there a way to just use the default value specified in the constructor of the Data class when the values are null?

I could not find anything in the documentation, but I was hoping something like this would work:

val data = Data(newName()?, newNumber()?)

But that does not compile.

Answer

mfulton26 picture mfulton26 · Jun 23, 2017

You can create a secondary constructor that uses the same default values when receiving null:

data class Data(
    val name: String = "",
    val number: Long = 0
) {
    constructor(
        name: String? = null,
        number: Long? = null
    ) : this(
        name ?: "",
        number ?: 0
    )
}

and if you are comfortable with your primary constructor being private you can avoid defining the defaults twice:

data class Data private constructor(
    val name: String,
    val number: Long
) {
    companion object {
        operator fun invoke(
            name: String? = null,
            number: Long? = null
        ) = Data(
            name ?: "",
            number ?: 0
        )
    }
}

this also enables calling Data() as it avoids an overload resolution ambiguity