Last active
November 11, 2022 16:29
-
-
Save rascio/daea8a9aad65dd90d52a5d224632e437 to your computer and use it in GitHub Desktop.
Kotlin parallel DSL
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fun main() = runBlocking { | |
val (first, second, third) = ( | |
parallel { | |
println("I/O") | |
delay(100) | |
"FIRSTRESULT" | |
} and { | |
println("I/O") | |
delay(100) | |
2 | |
} and { | |
"SOMETHINGELSE" | |
} | |
).await() | |
// types are maintained | |
first.uppercase() | |
second.inc() | |
third.lowercase() | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
inline fun <C> CoroutineScope.deferred(crossinline gen: suspend () -> C) = async { kotlin.runCatching { gen() } } | |
class Par1<A>(val value: A) { | |
companion object { | |
/** | |
* Create a parallel computation | |
*/ | |
suspend inline fun <A> parallel(crossinline gen: suspend () -> A) = | |
coroutineScope { | |
Par1(deferred(gen)) | |
} | |
/** | |
* Append another parallel function into the computation | |
*/ | |
suspend inline infix fun <A, B> Par1<Deferred<A>>.and(crossinline gen: suspend () -> B) = | |
coroutineScope { | |
Par2(value, deferred(gen)) | |
} | |
} | |
} | |
data class Par2<A, B>(val a: A, val b: B) { | |
companion object { | |
/** | |
* Append another parallel function into the computation | |
*/ | |
suspend inline infix fun <A, B, C> Par2<Deferred<A>, Deferred<B>>.and(crossinline gen: suspend () -> C) = | |
coroutineScope { | |
Par3(a, b, deferred(gen)) | |
} | |
/** | |
* Await computation and catch exceptions in a `Result` | |
*/ | |
suspend fun <A, B> Par2<Deferred<Result<A>>, Deferred<Result<B>>>.awaitResult() = Par2( | |
a.await(), | |
b.await() | |
) | |
/** | |
* Await and throws exception if something fail | |
*/ | |
suspend fun <A, B> Par2<Deferred<Result<A>>, Deferred<Result<B>>>.await() = awaitResult().let { | |
Par2(it.a.getOrThrow(), it.b.getOrThrow()) | |
} | |
/** | |
* Await and suppress exceptions | |
*/ | |
suspend fun <A, B> Par2<Deferred<Result<A>>, Deferred<Result<B>>>.awaitOrNull() = awaitResult().let { | |
Par2(it.a.getOrNull(), it.b.getOrNull()) | |
} | |
} | |
} | |
data class Par3<A, B, C>(val a: A, val b: B, val c: C) { | |
companion object { | |
/** | |
* Await computation and catch exceptions in a `Result` | |
*/suspend fun <A, B, C> Par3<Deferred<Result<A>>, Deferred<Result<B>>, Deferred<Result<C>>>.awaitResult() = Par3( | |
a.await(), | |
b.await(), | |
c.await() | |
) | |
/** | |
* Await and throws exception if something fail | |
*/ | |
suspend fun <A, B, C> Par3<Deferred<Result<A>>, Deferred<Result<B>>, Deferred<Result<C>>>.await() = awaitResult().let { | |
Par3(it.a.getOrThrow(), it.b.getOrThrow(), it.c.getOrThrow()) | |
} | |
/** | |
* Await and suppress exceptions | |
*/ | |
suspend fun <A, B, C> Par3<Deferred<Result<A>>, Deferred<Result<B>>, Deferred<Result<C>>>.awaitSafe() = awaitResult().let { | |
Par3(it.a.getOrNull(), it.b.getOrNull(), it.c.getOrNull()) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment