diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts index 97a9364..19e0571 100644 --- a/benchmarks/build.gradle.kts +++ b/benchmarks/build.gradle.kts @@ -23,6 +23,7 @@ kotlin { implementation(project(":kotlin-result-coroutines")) implementation(libs.kotlin.benchmark.runtime) implementation(libs.kotlin.coroutines.core) + implementation(libs.arrow) } } } diff --git a/benchmarks/src/commonMain/kotlin/com/github/michaelbull/result/BindingBenchmark.kt b/benchmarks/src/commonMain/kotlin/com/github/michaelbull/result/BindingBenchmark.kt index 7637d93..3755b3c 100644 --- a/benchmarks/src/commonMain/kotlin/com/github/michaelbull/result/BindingBenchmark.kt +++ b/benchmarks/src/commonMain/kotlin/com/github/michaelbull/result/BindingBenchmark.kt @@ -1,5 +1,10 @@ package com.github.michaelbull.result +import arrow.core.raise.either +import arrow.core.Either +import arrow.core.flatMap +import arrow.core.left +import arrow.core.right import kotlinx.benchmark.Benchmark import kotlinx.benchmark.BenchmarkMode import kotlinx.benchmark.BenchmarkTimeUnit @@ -36,6 +41,28 @@ class BindingBenchmark { blackhole.consume(result) } + @Benchmark + fun arrowBindingSuccess(blackhole: Blackhole) { + val result: Either = either { + val x = arrowProvideX().bind() + val y = arrowProvideY().bind() + x + y + } + + blackhole.consume(result) + } + + @Benchmark + fun arrowBindingFailure(blackhole: Blackhole) { + val result: Either = either { + val x = arrowProvideX().bind() + val z = arrowProvideZ().bind() + x + z + } + + blackhole.consume(result) + } + @Benchmark fun andThenSuccess(blackhole: Blackhole) { val result = provideX().andThen { x -> @@ -58,9 +85,35 @@ class BindingBenchmark { blackhole.consume(result) } + @Benchmark + fun arrowFlatMapSuccess(blackhole: Blackhole) { + val result = arrowProvideX().flatMap { x -> + arrowProvideY().flatMap { y -> + (x + y).right() + } + } + + blackhole.consume(result) + } + + @Benchmark + fun arrowFlatMapFailure(blackhole: Blackhole) { + val result = arrowProvideX().flatMap { x -> + arrowProvideZ().flatMap { z -> + (x + z).right() + } + } + + blackhole.consume(result) + } + private object Error private fun provideX(): Result = Ok(1) private fun provideY(): Result = Ok(2) private fun provideZ(): Result = Err(Error) + + private fun arrowProvideX(): Either = 1.right() + private fun arrowProvideY(): Either = 2.right() + private fun arrowProvideZ(): Either = Error.left() } diff --git a/benchmarks/src/jvmMain/kotlin/com/github/michaelbull/result/CoroutineBindingBenchmark.kt b/benchmarks/src/jvmMain/kotlin/com/github/michaelbull/result/CoroutineBindingBenchmark.kt index 54ed87c..d9a2ff3 100644 --- a/benchmarks/src/jvmMain/kotlin/com/github/michaelbull/result/CoroutineBindingBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/com/github/michaelbull/result/CoroutineBindingBenchmark.kt @@ -1,5 +1,8 @@ package com.github.michaelbull.result +import arrow.core.Either +import arrow.core.raise.either +import arrow.core.right import com.github.michaelbull.result.coroutines.coroutineBinding import kotlinx.benchmark.Benchmark import kotlinx.benchmark.BenchmarkMode @@ -10,6 +13,7 @@ import kotlinx.benchmark.OutputTimeUnit import kotlinx.benchmark.Scope import kotlinx.benchmark.State import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking @@ -37,6 +41,25 @@ class CoroutineBindingBenchmark { } } + @Benchmark + fun arrowNonSuspendableBinding(blackhole: Blackhole) { + blackhole.consume(nonSuspend().get()) + } + + @Benchmark + fun arrowSuspendableBinding(blackhole: Blackhole) { + runBlocking { + blackhole.consume(withSuspend().get()) + } + } + + @Benchmark + fun arrowAsyncSuspendableBinding(blackhole: Blackhole) { + runBlocking { + blackhole.consume(withAsyncSuspend().get()) + } + } + private object Error private val time = 100L @@ -78,4 +101,44 @@ class CoroutineBindingBenchmark { delay(time) return Ok(2) } + + private fun arrowNonSuspend(): Either = either { + val x = arrowProvideXBlocking().bind() + val y = arrowProvideYBlocking().bind() + x + y + } + + private suspend fun arrowWithSuspend(): Either = either { + val x = arrowProvideX().bind() + val y = arrowProvideY().bind() + x + y + } + + private suspend fun arrowWithAsyncSuspend(): Either = either { + coroutineScope { + val x = async { arrowProvideX().bind() } + val y = async { arrowProvideY().bind() } + x.await() + y.await() + } + } + + private fun arrowProvideXBlocking(): Either { + Thread.sleep(time) + return 1.right() + } + + private fun arrowProvideYBlocking(): Either { + Thread.sleep(time) + return 2.right() + } + + private suspend fun arrowProvideX(): Either { + delay(time) + return 1.right() + } + + private suspend fun arrowProvideY(): Either { + delay(time) + return 2.right() + } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index eadf7b7..2036897 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -20,6 +20,8 @@ ktor-serialization-jackson = { module = "io.ktor:ktor-serialization-jackson", ve ktor-server-content-negotiation = { module = "io.ktor:ktor-server-content-negotiation", version.ref = "ktor" } ktor-server-netty = { module = "io.ktor:ktor-server-netty", version.ref = "ktor" } +arrow = { module = "io.arrow-kt:arrow-core", version = "2.1.2" } + [plugins] kotlin-allopen = { id = "org.jetbrains.kotlin.plugin.allopen", version.ref = "kotlin" } kotlin-benchmark = { id = "org.jetbrains.kotlinx.benchmark", version.ref = "kotlin-benchmark" }