Youssef Shoaib [MOD]
05/22/2024, 11:58 AM@Multishot suspend fun
and make it so that the continuations that the special suspendCoroutineMultishot
provides always resumes a clone of the normal CPS continuation. I think that would be sufficient to implement multishot behaviour?raulraja
05/22/2024, 12:05 PMYoussef Shoaib [MOD]
05/22/2024, 12:45 PMYoussef Shoaib [MOD]
05/22/2024, 12:46 PMephemient
05/22/2024, 4:11 PMYoussef Shoaib [MOD]
05/22/2024, 4:13 PMsuspendCoroutineUninterceptedOrReturn
) stores your local variables in its fields (if you recall, suspend functions are compiled into state machines, represented by those continuations). If you can clone the state of the state machine (i.e its local variables and what steps its at), you can run the state machine multiple times. Again, all this would involve is just making a shallow copy of the fields of the state machine, nothing more.
In other words: I want to clone continuations, and shallowly at that. Not taking about general cloning of any value (that's obviously way more involved).ephemient
05/22/2024, 4:14 PM.use {}
resuming multiple times and closing the same resourceYoussef Shoaib [MOD]
05/22/2024, 4:17 PMephemient
05/22/2024, 4:18 PMsuspend
functions in nor call from normal suspend
functions) then what's the effective difference to @Composable
?Youssef Shoaib [MOD]
05/22/2024, 4:21 PMsuspend
functions inside, but suspend
functions can't call you. Just like how suspend functions can call pure functions but not the other way around. The difference to @Composable
is that @Composable
doesn't actually do a CPS transform or anything like that. In fact, I have implemented this in terms of @Composable
, and I've been able to get it to work with a few tricks, but one has to essentially rerun the function every time because there's no state machine. The performance suffers also vs a native solutionephemient
05/22/2024, 4:26 PMlaunchMolecule {
val value1 by flow1.collectAsState()
val value2 by flow2.collectAsState()
...
value1 + value2
}
by @Composable
ephemient
05/22/2024, 4:27 PMone has to essentially rerun the function every timewhy's that? it's chopped up into restartable segments
Youssef Shoaib [MOD]
05/22/2024, 4:30 PMflatMap
type of comprehension. Yes this type can be useful (and in fact would be supported by multishot continuations) but multishot continuations support more than what molecule can do.
> it's chopped up into restartable segments
That happens for composable function calls, but not for the code in between. If a composable gets invalidated, execution doesn't jump to the point where it was invalidated, it jumps to the block where it was invalidated. In your example, if you have a println
before a collectAsState
, that println
runs every single time the state updates, even though it occurs before you even collected the flow.
This can be worked around in Compose if you basically manually turn your function into a state machine. The way I do it is I have a special token `remember`ed for every shift point, and I wrap any side effect or pure-but-expensive-calculation into an effect{ }
block which memoises its results and only recalculates if the shift point we're resuming at has been reached.
This is messy and error-prone though, and the solution to do this with the pre-exisiting CPS transform is a lot simpler, it just needs cloning support.
This can be worked around withYoussef Shoaib [MOD]
05/22/2024, 4:38 PMraulraja
05/22/2024, 6:14 PM