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.
If no default value is declared explicitly, the default value is the null value. This usually makes sense because a null value can be considered to represent unknown data. In a table definition, default values are listed after the column data type.
Every optional parameter in the procedure definition must specify a default value. The default value for an optional parameter must be a constant expression. Every parameter following an optional parameter in the procedure definition must also be optional.
The thing with optional parameters is, they are BAD because they are unintuitive - meaning they do NOT behave the way you would expect it. Here's why: They break ABI compatibility ! so you can change the default-arguments at one place.
You can define a companion object for your data class and overload its invoke operator to use default values when null
is passed:
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
)
}
}
the secondary constructor only supports for the Nullable primitive properties. which means it will result in 2 same constructors if the property is not a primitive type, for example:
data class Data(val name: String) {
constructor(name: String? = null) : this(name ?: "foo");
// ^--- report constructor signature error
}
data class Data(val number: Long = 0) {
constructor(number: Long? = null) : this(number ?: 0)
// ^--- No problem since there are 2 constructors generated:
// Data(long number) and Data(java.lang.Long number)
}
an alternative way is using invoke
operator for that, for example:
data class Data(val name: String) {
companion object {
operator fun invoke(name: String? = null) = Data(name ?: "")
}
}
IF the class is not a data class, then you can lazy initializing properties from parameters, rather than define properties on the primary constructor, for example:
class Data(name: String? = null, number: Long? = null) {
val name = name ?: ""
val number = number ?: 0
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With