Ahmet Özcan
08/18/2025, 6:04 PMPavel Habžanský
08/19/2025, 8:08 AMUiState
to your Composables?Ahmet Özcan
08/19/2025, 8:38 AMPavel Habžanský
08/19/2025, 8:40 AMsetName()
on UiState
, it won't trigger an update and recomposition. You need to set the whole state using copy(name = "name")
I think.Ahmet Özcan
08/19/2025, 8:41 AMAhmet Özcan
08/19/2025, 8:43 AMPavel Habžanský
08/19/2025, 8:43 AMAhmet Özcan
08/19/2025, 8:45 AMAhmet Özcan
08/19/2025, 8:46 AMAhmet Özcan
08/19/2025, 8:47 AMAhmet Özcan
08/19/2025, 8:53 AMPavel Habžanský
08/19/2025, 8:56 AMsetName
method on UiState
? You don't need it. If anything, argument can be made it's wrong because it violates immutability of Kotlin data class.Pavel Habžanský
08/19/2025, 8:57 AMAhmet Özcan
08/19/2025, 8:57 AMgalex
08/19/2025, 2:40 PMAhmet Özcan
08/19/2025, 4:26 PMAhmet Özcan
08/19/2025, 4:34 PMAhmet Özcan
08/19/2025, 4:39 PMgalex
08/19/2025, 5:25 PMgalex
08/19/2025, 5:27 PMPavel Habžanský
08/19/2025, 5:28 PMstate = state.copy(value = newValue)
via VM methods. Overall State object in compose should not have any setters (again, coming back to data classes being immutable).
It doesn't randomly change properties of state, it's simple and very easy to test. I feel like this is generally used approach.Ahmet Özcan
08/19/2025, 5:43 PMPavel Habžanský
08/19/2025, 5:44 PMSabbib Chowdhury
08/19/2025, 11:02 PM@Immutable
? it seems to fundamentally break the concept of data classes.
also, does "do things in different ways then we always do" justify breaking fundamental concepts?
thinking about it in other directions, can the lambda also return a non-Unit
type, i.e. is this acceptable: val returnAction: () -> String
could the lambda be of type generic:
val genAction: T.() -> Unit
or val genAction: (T) -> Unit
Ahmet Özcan
08/20/2025, 7:45 AMAhmet Özcan
08/20/2025, 7:46 AMAhmet Özcan
08/20/2025, 7:47 AMPavel Habžanský
08/20/2025, 7:50 AMPavel Habžanský
08/20/2025, 7:50 AMAhmet Özcan
08/20/2025, 7:51 AMAhmet Özcan
08/20/2025, 7:52 AMAhmet Özcan
08/20/2025, 7:54 AMPavel Habžanský
08/20/2025, 7:55 AMstate.setName(nmae)
). I can paint a tomato green but it still will be a tomato.
That's another thing btw, why do you think it's better to pass function reference to state instead of calling VM methods directly in composables?Ahmet Özcan
08/20/2025, 7:56 AMAhmet Özcan
08/20/2025, 7:56 AMAhmet Özcan
08/20/2025, 7:57 AMAhmet Özcan
08/20/2025, 7:58 AMAhmet Özcan
08/20/2025, 7:59 AMAhmet Özcan
08/20/2025, 8:03 AMAhmet Özcan
08/20/2025, 8:04 AMPavel Habžanský
08/20/2025, 8:04 AMdata class State(
val remainingTime: Int = 30
) {
val isResendButtonVisible: Boolean
get() = remainingTime < 15
}
Pavel Habžanský
08/20/2025, 8:04 AMclass TimeViewModel : ViewModel() {
private fun countdown(duration: Duration): Flow<Duration> = flow {
var timeLeft = duration
while (timeLeft > 0.seconds) {
emit(timeLeft)
timeLeft -= 1.seconds
delay(1000)
}
emit(0.seconds)
}
fun startCountdown() {
viewModelScope.launch {
countdown(30.seconds).collect { timeLeft ->
state = state.copy(remainingTime = timeLeft)
}
}
}
data class State(
val remainingTime: Int = 30
) {
val isResendButtonVisible: Boolean
get() = remainingTime < 15
}
}
Pavel Habžanský
08/20/2025, 8:04 AMAhmet Özcan
08/20/2025, 8:07 AMPavel Habžanský
08/20/2025, 8:08 AMremainingTime
in state isAhmet Özcan
08/20/2025, 8:08 AMPavel Habžanský
08/20/2025, 8:09 AMAhmet Özcan
08/20/2025, 8:10 AMAhmet Özcan
08/20/2025, 8:11 AMPavel Habžanský
08/20/2025, 8:19 AMeventSink
in Circuit?Ahmet Özcan
08/20/2025, 8:21 AMAhmet Özcan
08/20/2025, 8:21 AMPavel Habžanský
08/20/2025, 8:22 AMAhmet Özcan
08/20/2025, 8:23 AMAhmet Özcan
08/20/2025, 8:23 AMAhmet Özcan
08/20/2025, 8:23 AMPavel Habžanský
08/20/2025, 8:25 AMfun onEvent(event: Event) {
when (event) {
...
}
}
sealed class Event {
...
}
but the onEvent
function was part of VM. I used to like it but today I think it's not as readable as updating State in smaller functionsAhmet Özcan
08/20/2025, 8:25 AMAhmet Özcan
08/20/2025, 8:26 AMAhmet Özcan
08/20/2025, 8:27 AMjuliocbcotta
08/20/2025, 10:45 AMAhmet Özcan
08/20/2025, 11:51 AMjuliocbcotta
08/20/2025, 11:55 AMAhmet Özcan
08/20/2025, 12:10 PMjuliocbcotta
08/20/2025, 12:13 PMAhmet Özcan
08/20/2025, 12:14 PMsharif saleh
10/01/2025, 10:21 AMAhmet Özcan
10/01/2025, 11:20 AMAhmet Özcan
10/01/2025, 11:21 AMAhmet Özcan
10/01/2025, 11:22 AMsharif saleh
10/01/2025, 11:48 AMUiState
.
functions are not data; they produce values when executed
in Kotlin, data classes are meant to hold only data, and the compiler generates key methods for them
like (equals()
and hashCode()
) based on the properties in the primary constructor
if you include functions as properties, you break the core contract of a data class
,
and those generated methods will no longer behave correctly.
take a look at the last two points he mentioned:
• Store lambdas separately from data classes when object equality matters
• Override equals and hashCode carefully to exclude fields that could vary unexpectedly, or you know don’t matter to your equality.Ahmet Özcan
10/01/2025, 11:55 AMAhmet Özcan
10/01/2025, 11:56 AMdata class MyData(val name: String, val action: () -> Unit)
fun main() = runBlocking {
val v1 = MyData("Test", ::test)
val v2 = MyData("Test", ::test)
println(v1 == v2)
}
fun test(){}
Ahmet Özcan
10/01/2025, 11:56 AMAhmet Özcan
10/01/2025, 11:57 AMAhmet Özcan
10/01/2025, 11:58 AMPavel Habžanský
10/01/2025, 11:58 AMAhmet Özcan
10/01/2025, 11:59 AMPavel Habžanský
10/01/2025, 12:01 PMAhmet Özcan
10/01/2025, 12:01 PMPavel Habžanský
10/01/2025, 12:02 PMSabbib Chowdhury
10/01/2025, 12:02 PMAhmet Özcan
10/01/2025, 12:02 PMSabbib Chowdhury
10/01/2025, 12:05 PMprotect events in states so you cannot take any other actions.
how do you mean protect? and how do you mean take any other actions?
Ahmet Özcan
10/01/2025, 12:06 PMSabbib Chowdhury
10/01/2025, 12:07 PMAhmet Özcan
10/01/2025, 12:08 PMAhmet Özcan
10/01/2025, 12:20 PMAhmet Özcan
10/01/2025, 12:25 PMSabbib Chowdhury
10/01/2025, 10:31 PMAhmet Özcan
10/02/2025, 6:28 AMAhmet Özcan
10/02/2025, 6:30 AMPavel Habžanský
10/02/2025, 6:33 AMfun run() {
if (!state.body.hasLegs) return
run.invoke()
}
Pavel Habžanský
10/02/2025, 6:33 AMAhmet Özcan
10/02/2025, 6:34 AMAhmet Özcan
10/02/2025, 6:34 AMPavel Habžanský
10/02/2025, 6:35 AMAhmet Özcan
10/02/2025, 6:36 AMAhmet Özcan
10/02/2025, 6:36 AMAhmet Özcan
10/02/2025, 6:37 AMPavel Habžanský
10/02/2025, 6:37 AMeventSink
method?Ahmet Özcan
10/02/2025, 6:38 AMAhmet Özcan
10/02/2025, 6:38 AMPavel Habžanský
10/02/2025, 6:39 AMAhmet Özcan
10/02/2025, 6:39 AMAhmet Özcan
10/02/2025, 6:40 AMPavel Habžanský
10/02/2025, 6:40 AMPavel Habžanský
10/02/2025, 6:40 AMAhmet Özcan
10/02/2025, 6:41 AMAhmet Özcan
10/02/2025, 6:41 AMAhmet Özcan
10/02/2025, 6:43 AMAhmet Özcan
10/02/2025, 6:44 AMPavel Habžanský
10/02/2025, 6:44 AMPavel Habžanský
10/02/2025, 6:45 AMAhmet Özcan
10/02/2025, 6:46 AMAhmet Özcan
10/02/2025, 6:46 AMAhmet Özcan
10/02/2025, 6:46 AMPavel Habžanský
10/02/2025, 6:47 AMeventSink
public in viewmodel and not pass it to UiState, it's an appraoch, it's ok to pass events if it feels good to you, great but don't tell me you don't like guards when you're checking for all the states in when
.
No problem arises if you write tests.Pavel Habžanský
10/02/2025, 6:47 AMAhmet Özcan
10/02/2025, 6:48 AMAhmet Özcan
10/02/2025, 6:49 AMSabbib Chowdhury
10/02/2025, 6:50 AMAhmet Özcan
10/02/2025, 6:50 AMAhmet Özcan
10/02/2025, 6:51 AMSabbib Chowdhury
10/02/2025, 6:51 AMSabbib Chowdhury
10/02/2025, 6:52 AMPavel Habžanský
10/02/2025, 6:52 AMPavel Habžanský
10/02/2025, 6:53 AMSabbib Chowdhury
10/02/2025, 6:53 AMAhmet Özcan
10/02/2025, 6:54 AMAhmet Özcan
10/02/2025, 6:55 AMPavel Habžanský
10/02/2025, 6:55 AMAhmet Özcan
10/02/2025, 6:56 AMAhmet Özcan
10/02/2025, 6:56 AMAhmet Özcan
10/02/2025, 6:57 AMPavel Habžanský
10/02/2025, 7:00 AMwhen (event)
check is also a guard. You still need to check the event to know what to call. Yes, I;m checking conditions in my code, that's absolutely natural thing to do.
As I said, passing events is fine imo, if you like it, great, but I really feel like you're trying to point out the weirdest reasons to why what you're proposing is better. 😄Sabbib Chowdhury
10/02/2025, 7:01 AMSabbib Chowdhury
10/02/2025, 7:01 AMPavel Habžanský
10/02/2025, 7:01 AMAhmet Özcan
10/02/2025, 7:01 AMSabbib Chowdhury
10/02/2025, 7:02 AMPavel Habžanský
10/02/2025, 7:02 AMSabbib Chowdhury
10/02/2025, 7:03 AMSabbib Chowdhury
10/02/2025, 7:03 AMAhmet Özcan
10/02/2025, 7:04 AMAhmet Özcan
10/02/2025, 7:05 AMSabbib Chowdhury
10/02/2025, 7:05 AMSabbib Chowdhury
10/02/2025, 7:06 AMSabbib Chowdhury
10/02/2025, 7:07 AMAhmet Özcan
10/02/2025, 7:08 AMAhmet Özcan
10/02/2025, 7:08 AMSabbib Chowdhury
10/02/2025, 7:08 AMAhmet Özcan
10/02/2025, 7:10 AM