dimsuz
02/03/2022, 1:46 PMcombine
, but no top-level zip
. I have a List<Flow<Int>>
and want to zip them, what is my best option?gildor
02/03/2022, 2:44 PMephemient
02/03/2022, 7:34 PMfun zip3(a, b, c) = a.zip(b).zip(c) { (a, b), c -> Triple(a, b, c) }
or have a more efficient implementation of the same signature, but there is no larger heterogeneous tuple type… what should zip4/zip5/etc. return?ephemient
02/03/2022, 7:36 PMgildor
02/04/2022, 1:45 AMdimsuz
02/04/2022, 10:09 AMdimsuz
02/04/2022, 10:12 AMcombine
and also usually these many-values combinators are present in libraries supporting zip: rx has this, haskell's stdlib has this, scala etc etc. Coroutines have this for combine, but not for zip.gildor
02/04/2022, 10:12 AMgildor
02/04/2022, 10:14 AMdimsuz
02/04/2022, 10:15 AM1finished 2finished 3finished -> combined result
1finished 2finished 3finished -> combined result
combine would give me
1finished 2finished 3finished -> combined result
1finished -> combined result
2finished -> combined result
3finished -> combined result
I.e. I need zip's semantics which waits for all to complete in stages.gildor
02/04/2022, 10:15 AMthose tasks are restartable, I nned this behaviourSo all your 3 separate flows are restarting and every time you want to combine their latest result?
gildor
02/04/2022, 10:16 AMgildor
02/04/2022, 10:17 AMgildor
02/04/2022, 10:18 AMgildor
02/04/2022, 10:18 AMgildor
02/04/2022, 10:19 AMinterface Task<T> {
fun start(): Flow<Either<T, Throwable>>
}
gildor
02/04/2022, 10:19 AMgildor
02/04/2022, 10:19 AMinterface Task<T> {
fun start(): Either<T, Throwable>
}
gildor
02/04/2022, 10:19 AMdimsuz
02/04/2022, 10:35 AMFlow
without needing to know about start()
. One screen calls start, other screens get result reactively. It's a very common pattern for us which was derived across several years of writing very complex apps. For example I've seen this pattern also in Chris Banes' tivi sample but it's not yet organized there, it has start() and flows separately in interfaces, they often go together. We have only observed this and bundled them neatly, which simplified the code.gildor
02/04/2022, 10:39 AMWell, this separation of results state flow and start() allows to build highly declarative UI’s,I don’t agree with this, it’s not declarative
gildor
02/04/2022, 10:39 AMAlso multiple screens can be subscribed to thisÂBut what is actual use case of this? To know about all restring requests? without needing to know aboutÂFlow
start()
gildor
02/04/2022, 10:40 AMgildor
02/04/2022, 10:41 AMgildor
02/04/2022, 10:41 AMdimsuz
02/04/2022, 10:45 AMBut what is actual use case of this?I have a setting screen which starts an upload, show loader, then return to pervious screen which shows all active uploads. they both are subscribed to
task.state
and show current loading state. other screens a free to do so to. also both screens can have button to "restart" failed upload, which has onClick = { task.start() }
In the issue I've outlined only what's important for the issue. Of course we also have val state: Flow<TaskState> // idle/working
dimsuz
02/04/2022, 10:45 AMmissing such a basic thing as cancellation or handling of multiple start() (should it restart? should it throw error?)we have all this. Task is a building block, while there's a framework around this.
dimsuz
02/04/2022, 10:50 AMstate: Flow<Idle|Running>
and results: Flow<Either>
and Task
is the thing adding a start()
to it which was born out of observation that many-many screen operations are restartable: fetching content (initially and after pull-to-refresh), etc etc. Task is not necessarily used everywhere, but pair of state+results is used often.dimsuz
02/04/2022, 11:00 AMI don’t agree with this, it’s not declarativePrepared a tiny (simplified) example. Do you think this is not declarative? https://gist.github.com/dimsuz/179d50e4eb04a0e5dba2928362429cb4 Task is not a UI state construct (you seem to think that), it's from "domain" layer, more generic. UI only happens to render some of its state and call some of its methods as a side-effects.