I have a suspend function that executes a long asy...
# coroutines
t
I have a suspend function that executes a long async operation that should periodically report progress to the caller. According to you, what would be the best way to model that ? 1️⃣
suspend fun doWork(progress: (Progress) -> Unit)
2️⃣
fun doWork(): Flow<Progress>
3️⃣
fun doWorkIn(scope: CoroutineScope): StateFlow<Progress>
4️⃣ Anything else (please explain in comments !)
2️⃣ 12
1️⃣ 1
g
Depends on case, usually 1️⃣ is enough, but for some cases also use 2️⃣ , but also often provide helper method which awaits final result Also, all you samples do not return result, which usually what you want from long async operation, so usage of Flow becomes more cumbersome, this why often prefer progress lambda Tho, Flow is more universal API
e
Progress
could be a sealed class where it's either partially done, or the completed result (or even an error if that is a result). That would play nicely with option 2, so you can collect progress updates and ultimately the flow completes with a result or error.
g
Yes, Sealed class what we use with Flow and RxJava, but it really not the best API in terms of usability
d
Not sure I understand the reasoning behind option 1. In part, coroutines is a means to escape callbacks, sporting direct programming. Combining
suspend
and a callback seems like a paradigm collision.
b
@d4vidi did you see
flow.collect
signature? 🙂 You will pass callback in both 1️⃣ and 2️⃣
1
g
I don't see any collision, all flow API is also based on callbacks, as Denis pointed out, it's not very nice looking, I completely agree, it's just practical in many cases (at least for UI), where progress is just a side effect, so you put pass lambda to get progress if you want receive callback notifications for logging it or show in UI, you even can make it optional, so it doesn't disturb users of this api when you don't care about progress
d
@bezrukov right, I don’t know how I missed that. Thanks.