What’s the best way to modify a nested property in...
# getting-started
d
What’s the best way to modify a nested property in an immutable data class object?
Copy code
data class AppState (
    val masterState : MasterState = MasterState(),
)
data class MasterState (
    val isLoading : Boolean = false,
)
is there a more concise way than this?
Copy code
val myState = AppState()
val newState = myState.copy(masterState = myState.masterState.copy(isLoading = true))
e
https://arrow-kt.io/docs/optics/lens/ is a more concise way (although also more magical)
d
I wanted to create a very simple function like
updateSubstate
, where I could perform the substate copy inside the block, and the root state copy inside the function:
Copy code
// this is the specific function
fun MyModel.anExtensionFunction() {
	updateSubstate {
	     it.masterState.copy(isLoading = true)
	}
}
but I don’t know how to deal with the reflection:
Copy code
class MyModel {
    var myState = AppState()

    // this is the generic function
    fun updateSubstate(block: (AppState) -> Any) {
        val output = block(myState)
	...
        myState = myState.copy(PROPERTY_NAME_TO_GET_FROM_BLOCK_BETWEEN_IT_AND_COPY = output)
    }

}
e
Copy code
val copyFunction = AppState::copy
val thisParameter = copyFunction.parameters.find { it.kind == INSTANCE }!!
val propertyParameter = copyFunction.parameters.find { it.name == parameterName }!!
myState = copyFunction.callBy(mapOf(thisParameter to myState, propertyParameter to output))
but (as all things reflection) there is no safety here. do you really need to do this?
d
thanks! does this just work on JVM or on all platforms?
I am running it in CommonMain and the IDE can’t find many properties. Do I need to import Reflect as a dependency too?
I think I found a good solution, even without reflection, cleaner than before:
Copy code
updateMasterState {
    it.copy(isLoading = true)
}
even if I have to create a function for each substate:
Copy code
fun updateMasterState(block: (MasterState) -> MasterState) {
    myState = myState.copy(masterState = block(myState.masterState))
}