Couldn't these be inline too: ```public fun <T> Mu...
# arrow-contributors
d
Couldn't these be inline too:
Copy code
public fun <T> MutableState<T>.updateCopy(block: Copy<T>.() -> Unit) {
  update { it.copy(block) }
}

/**
 * Updates the value in this [MutableStateFlow]
 * by performing the operations in the [Copy] [block].
 */
public fun <T> MutableStateFlow<T>.updateCopy(block: Copy<T>.() -> Unit) {
  update { it.copy(block) }
}
the update functions themselves are and would allow to call suspend funs from within them... so if these were too, we could use the current ui state to call the suspend fun and update it atomically...
s
The update function can be executed multiple times. So it has to be pure. You don't wanna do side effects there
d
So what do you do if you need to update the ui based on it's previous state and the result of a side effect @stojan?
s
You execute the side effect outside the update function. Then you update the state based on the previous value + result which, which is a pure function
d
The parameters of the side-effect are based on the current state...
And also, in what way is update { } atomic then?
s
Updates the MutableStateFlow.value atomically using the specified function of its value.
function may be evaluated multiple times, if value is being concurrently updated.
source: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/update.html
d
Yeah, I saw that, but I'm wondering what's the use if not for a case like mine? There's a really simple case when a state needs to be computed based on it's past state, but then what could I do in my case?
I guess I could technically use a Mutex... but I'd need to wrap all the calls to my ui state with it... 🤕
One way or another, that comment is only if I'd be updating concurrently with that same function lambda (not when I call update throughout the code), but if I'd be careful it wouldn't happen. You're right that it's not so nice to do such a thing though...
s
it's hard to answer that question without a more concrete example.... there are multiple solutions with different tradeoffs
d
Copy code
uiState.update { prev ->
  val foo = someService.getFoo(prev.id)
  
  prev.copy(foo = foo)
}
s
one solution is:
Copy code
val foo = someService.getFoo(uiState.value.id)
uiState.update { prev -> prev.copy(foo == foo) }
now, the
update
function is pure, and safe to execute multiple times
d
But that takes the chance that uiState changed between uiState.value and the update...
So it could be the wrong foo...
(That's what I ended up doing before posting this question... but it would be nice to have something a bit better...)
s
as I mentioned before, there are multiple solutions, all with different trade offs. There is no single best solution for all cases. e.g. the code I posted works well for an android app, where the API call would be a result of a button click as the button will be disabled during the API call. you seem to be searching for a solution that works for everything, AFIK there is no such solution available. for a specific solution for your concrete problem, you'd have to post a concrete example
d
I understood that... I was just looking for a solution for a real atomic update with a side effect involved... the concrete example is a bit too involved to post here... of course there's no BEST solution out there, and I did the technique you posted up there already in a few places where it wasn't too critical.. I guess I'll have to avoid side-effects like you side and find another solution, thanks!