Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes recover inconsistency with raise DSL on types other than Either #3052

Merged
merged 11 commits into from
Jun 1, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ public class IorRaise<Error> @PublishedApi internal constructor(
map { it.bind() }

@RaiseDSL
public fun <A> Ior<Error, A>.bind(): A =
public override fun <A> Ior<Error, A>.bind(): A =
when (this) {
is Ior.Left -> raise(value)
is Ior.Right -> value
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package arrow.core.raise

import arrow.core.Either
import arrow.core.Ior
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This import is no longer required

Suggested change
import arrow.core.Ior
import arrow.core.Ior

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected.

import arrow.core.NonEmptyList
import arrow.core.NonEmptySet
import arrow.core.Validated
Expand Down Expand Up @@ -238,6 +239,14 @@ public interface Raise<in Error> {
is Either.Right -> value
}

@RaiseDSL
public fun <A> Ior<Error, A>.bind(): A =
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I came to the idea of doing this from studying why either { recover({ ... }) { ... } } works correctly. This ensures that in the recover block we hit this bind() if we reference bind() vs the one on IorScope. This allows recover to work in the way it does for either. However, the downside of this is, we do nothing with Ior.Both's left value which may be undesirable.

Originally I tried adding a new recover(...) method to IorRaise but couldn't quite get that to work right without more major changes. However, I might have missed something there.

Furthermore, the issue identified with Ior will happen with any other data type that has its own Raise variant. So NullableRaise OptionRaise etc. I didn't want to start making changes for that as I wanted to keep the discussion focused on the core problem. However, it's worth considering on this PR for sure.

when (this) {
is Ior.Left -> raise(value)
is Ior.Right -> value
is Ior.Both -> rightValue
}

public fun <K, A> Map<K, Either<Error, A>>.bindAll(): Map<K, A> =
mapValues { (_, a) -> a.bind() }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,11 @@ package arrow.core.raise
import arrow.core.Either
import arrow.core.Ior
import arrow.core.test.nonEmptyList
import arrow.typeclasses.Semigroup
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.shouldBe
import io.kotest.property.Arb
import io.kotest.property.arbitrary.filter
import io.kotest.property.arbitrary.int
import io.kotest.property.arbitrary.list
import io.kotest.property.arbitrary.string
import io.kotest.property.checkAll
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
Expand Down Expand Up @@ -79,4 +75,13 @@ class IorSpec : StringSpec({
}
}.message shouldBe "Boom!"
}

"Recover works as expected" {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This highlights the problem in the issue. This test fails without the change above.

ior(String::plus) {
val one = recover({ Ior.Left("Hello").bind() }) { 1 }
val two = Ior.Right(2).bind()
val three = Ior.Both(", World", 3).bind()
one + two + 3
yoxjames marked this conversation as resolved.
Show resolved Hide resolved
} shouldBe Ior.Both(", World", 6)
}
})