simon.vergauwen
02/28/2023, 8:35 PMparTupled and it couldn't be resolved without providing CoroutineContext π€ Did you encounter something like this while you were working on the PR?julian
02/28/2023, 9:21 PMCoroutineContext. I don't know how that even happened.
I didn't encounter the problem because I wasn't looking for it π
. I only implemented the `parTupled`s that require a CoroutineContext, or in absence of one, force named parameters to be used.
Sorry about that.
I can provide another PR for the missing functions.simon.vergauwen
03/02/2023, 2:11 PMparZip accidentally overwrites <http://Dispatchers.IO|Dispatchers.IO>. I.e.
withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
parZip({ io() }, { otherIO() }) { a, b -> ... }
}
While in contrast that doesn't happen with other functionality in KotlinX, so it's not really in line with each-other.
So all the Dispatchers.Default overloads should actually be deprecated. They should be needed at all..
Curious if this improves the situation with parTupled... Or the overloading syntax with Tuple .. I personally think overloading parZip with 18 methods just for tupling is a tad much π I was already a bit on the fence when it was 9 methods.simon.vergauwen
03/02/2023, 5:20 PMparZip and parTupled π Pfft that sucks..simon.vergauwen
03/02/2023, 5:22 PMctx: CoroutineContext = EmptyCoroutineContext.julian
03/02/2023, 5:23 PMparTupled to this sort of thing:
public suspend inline fun <A, B> parTupled(
crossinline fa: suspend CoroutineScope.() -> A,
crossinline fb: suspend CoroutineScope.() -> B,
): Pair<A, B>julian
03/02/2023, 5:25 PMparTupled?simon.vergauwen
03/02/2023, 5:55 PMcoroutineScope { awaitAll(async { }, ..., ...) }. I have to periodically remind/re-check myself why we have these methods π
TL;DR provide awaitAll behavior over suspend fun, which is consistent across Job and SupervisorJob. Running a bunch of different tests now, and I am again running in some unexpected scenarios π
I guess parZip provides a simpler model for parallelism.. I need to write a long document on this, I keep forgetting details after not working with low-level KotlinX for a long time π€simon.vergauwen
03/02/2023, 5:59 PMsuspend fun one(): Int = delay(1000).let { 1 }
suspend fun two(): Int =
throw RuntimeException("Boom!")
coroutineScope {
measureTimedValue {
kotlin.runCatching {
val fa = async { one() }
val fb = async { two() }
fa.await() + fb.await()
}
}.let(::println)
}
I was expecting that runCatching here captures RuntimeException but the first await throws JobCancellationException, and then coroutineScope rethrows the RuntimeException.
Whereas:
coroutineScope {
measureTimedValue {
kotlin.runCatching {
parZip({ one() }, { two() }) { a, b -> a + b }
}
}.let(::println)
}
Here I can capture the RuntimeException since awaitAll (used in parZip) throws RuntimeException and cancels-and-joins the others async internally first.simon.vergauwen
03/02/2023, 6:02 PMcoroutineScope with supervisorScope then the supervisorScope { async { } } snippet takes 1.second instead of failing fast. Which is expected by supervisorScope but parZip provides consistent semantics in this case again through awaitAll.
Although this is expected of supervisorScope { } when a function is defined suspend fun CoroutineScope (which is actually illegal to have both suspend and CoroutineScope) the behavior depends on the caller.simon.vergauwen
03/02/2023, 6:03 PMparZip though π€ I use it frequently, but that's probably because I am biased and used to it π It's also consistent to what I know from other FP langs.simon.vergauwen
03/02/2023, 6:03 PMjulian
03/02/2023, 6:14 PMwhen a function is defineddo you mean an extension function withsuspend fun CoroutineScope
CoroutineScope as receiver?simon.vergauwen
03/02/2023, 6:15 PMsimon.vergauwen
03/02/2023, 6:16 PMCancellationException is thrown. Then it's prone to hanging in some cases but SupervisorJob can also cause that in some edge-cases.simon.vergauwen
03/02/2023, 6:17 PMjulian
03/02/2023, 6:20 PMparZip much, myself. But I'm probably not the typical Arrow user - I don't get to use Arrow at my job. I don't really have a strong position. Nor a strong grasp of the trade-offs, if I'm being honest.julian
03/02/2023, 6:21 PMsimon.vergauwen
03/02/2023, 6:22 PMparTupled for now. We can always re-raise your PR and add it later. Removing it later is harder.
Well, you not using Arrow makes that you have good insight and might be able to provide good feedback here. Did you ever encounter any of the problems I described above, while working or in production and would you rather use parZip?simon.vergauwen
03/02/2023, 6:23 PMjulian
03/02/2023, 6:28 PMI really hate throwing people's work and effort awayThank you for caring. It's fine, though. Sometimes one must do a thing to really know what a thing means in context. That's just life, right? π
simon.vergauwen
03/02/2023, 6:34 PMsimon.vergauwen
03/02/2023, 6:34 PMjulian
03/02/2023, 6:35 PMsimon.vergauwen
03/02/2023, 6:38 PMjulian
03/02/2023, 6:40 PMparZip if I was unsure about how awaitAll behaves relative to coroutineScope vs supervisorScope . Or I was pressed for time and didn't want to have to experiment to find out. But folks more expert in coroutines might opt to be more explicit/transparent and skip parZip in favor of awaitAll.julian
03/02/2023, 6:41 PMjulian
03/02/2023, 6:42 PMwe're moving the meeting to 4pm CESTThat's great news! π₯³ Thank you all!
simon.vergauwen
03/02/2023, 6:46 PMEspecially if they're confident of the expertise of their code-reading audience.I guess it's a trade-off between more low-level vs external library... More flexibility vs less error-prone. Thread/Executor vs ReactiveX/IO
simon.vergauwen
03/03/2023, 10:34 AMparTupled when I was writing new documentation and working on the KotlinConf workshop. Super curious what you think about this API. If you're interested on working on this I'd be super happy to help and guide you βΊοΈ
https://github.com/arrow-kt/arrow/pull/2957julian
03/03/2023, 3:06 PM