Skip to content

Instantly share code, notes, and snippets.

@rascio
Last active November 11, 2022 16:29
Show Gist options
  • Save rascio/daea8a9aad65dd90d52a5d224632e437 to your computer and use it in GitHub Desktop.
Save rascio/daea8a9aad65dd90d52a5d224632e437 to your computer and use it in GitHub Desktop.
Kotlin parallel DSL
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()
}
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