If I have a function or constructor in Kotlin, how do I omit certain parameters with a conditional? For example:
val capture = ScaleCapture(
if (jsonObject.has(JSON.ID))
id = jsonObject.getInt(JSON.ID),
if (jsonObject.has(JSON.WEIGHT))
weight = jsonObject.getInt(JSON.WEIGHT)
)
//...
data class ScaleCapture(
val id: Int = 0
)
What I want is to ensure that, rather than sending a null value for a given parameter, the parameter is omitted entirely at the call site, which allows the default value to be used. If a function has multiple parameters with default values, it would be cumbersome to write out every possible combination of available parameters:
// Example with 2 parameters with default values
// We cannot pass null values because this is not the same as an omission due to default parameter values
if (jsonObject.has(JSON.ID)) {
if (jsonObject.has(JSON.WEIGHT)) {
return ScaleCapture(
id = jsonObject.getInt(JSON.ID),
weight = jsonObject.getInt(JSON.WEIGHT))
} else {
return ScaleCapture(
id = jsonObject.getInt(JSON.ID)
} else if(jsonObject.has(JSON.WEIGHT)) {
return ScaleCapture(
weight = jsonObject.getInt(JSON.WEIGHT))
} else {
return ScaleCapture()
}
//...
data class ScaleCapture(
val id: Int = 0,
val data: Int = 0
)
How do I accomplish this? I checked the Kotlin documentation under default values, but there wasn't much information.
Just for the sake of argument, there are two other options.
Just go for mutable state:
data class ScaleCapture(
var id: Int = 0,
var data: String = "",
)
val scaleCapture = ScaleCapture()
if (jsonObject.has(JSON.ID)) scaleCapture.id = jsonObject.getInt(JSON.ID)
if (jsonObject.has(JSON.WEIGHT)) scaleCapture.data = jsonObject.getString(JSON.WEIGHT)
If you want the ScaleCapture to be immutable, you could also opt by going the full-fledged reflection way:
data class ScaleCapture(
val id: Int = 0,
val data: String = "",
)
val parameters = mutableMapOf<KParameter, Any>()
if (jsonObject.has(JSON.ID)) parameters.put(primaryConstructor.parameters.first { it.name == "id" }, jsonObject.getInt(JSON.ID))
if (jsonObject.has(JSON.WEIGHT)) parameters.put(primaryConstructor.parameters.first { it.name == "data" }, jsonObject.getString(JSON.WEIGHT))
val primaryConstructor = ScaleCapture::class.primaryConstructor!!
val scaleCapture = primaryConstructor.callBy(parameters)
I like immutability a lot, but using reflection is super dirty. Personally I would create two types. The first mutable and the next immutable:
private data class MutableScaleCapture(
var id: Int = 0,
var data: String = "",
)
data class ScaleCapture(
val id: Int,
val data: String,
)
Then you can just map the mutable one to an immutable and expose that one to the rest of your application:
val capture = MutableScaleCapture()
// if (jsonObject.has(JSON.ID)) scaleCapture.id = <something>
// .. etc
ScaleCapture(capture.id, capture.data)