Jan
07/24/2023, 12:58 PMensure etc). My understanding is that you should Either.catch {} & bind() inside an either {}.
We would like to avoid repeating that catch&bind. Is that a bad idea? What is the recommended way here? See thread for our current solution.Jan
07/24/2023, 12:59 PMinline fun <Error : Any, A> boundary(
onCatch: (Throwable) -> Error,
@BuilderInference block: Raise<Error>.() -> A
): Either<Error, A> = fold(
block,
{ Either.Left(onCatch(it)) },
{ Either.Left(it) },
{ Either.Right(it) }
)CLOVIS
07/24/2023, 1:12 PMÈither.catch {
block()
}.mapLeft { onCatch(it) }simon.vergauwen
07/24/2023, 1:17 PMbind in this case if you want, but that restricts it to being used inside either { }.
inline fun <Error : Any, A> Raise<Error>.boundary(
onCatch: (Throwable) -> Error,
@BuilderInference block: Raise<Error>.() -> A
): A = fold(
block,
{ raise(onCatch(it)) },
{ raise(it) },
{ it }
)
Otherwise I would indeed just use the code that @CLOVIS shared.Jan
07/24/2023, 1:48 PMEither.catch I don't have the Raise DSL, do I? We would like to use both ensure as well as having a catch-all behaviour.
operator fun invoke(foo: Int): Either<String, Int> = either {
ensure(foo > 0) { "Foo must be positive" }
val result = Either.catch { someMethodThatCanThrow(foo) }.mapLeft { "Unknown" }.bind()
ensureNotNull(result) { "Unexpected null" }
Either.catch { yetAnotherCanThrow(result) }.mapLeft { "Unknown" }.bind()
}
// vs
operator fun invoke(foo: Int): Either<String, Int> = boundary({ "Unknown" }) {
ensure(foo > 0) { "Foo must be positive" }
val result = someMethodThatCanThrow(foo)
ensureNotNull(result) { "Unexpected null" }
yetAnotherCanThrow(result)
}CLOVIS
07/24/2023, 1:59 PMfun <E, T> Raise<E>.catch(onError: (Throwable) -> E, block: () -> T): T =
Either.catch(block)
.mapLeft(onError)
.bind()
Usage:
òperator fun invoke(foo: Int): Either<String, Int> = either {
ensure(foo > 0) { "Foo must be positive" }
val result = catch(onError = { "Unknown" }) { someMethodThatCanThrow(foo) }
ensureNotNull(result) { "Unexpected 'null'" }
catch({ "Unknown" }) { yetAnotherCanThrow(result) }
}CLOVIS
07/24/2023, 2:00 PMwithError :
fun <T> Raise<Throwable>.catch(block: () -> T): T =
Either.catch(block)
.bind()
Usage:
òperator fun invoke(foo: Int): Either<String, Int> = either {
ensure(foo > 0) { "Foo must be positive" }
val result = withError({ "Unknown" }) { catch { someMethodThatCanThrow(foo) } }
ensureNotNull(result) { "Unexpected 'null'" }
withError({ "Unknown" }) { catch { yetAnotherCanThrow(result) } }
}CLOVIS
07/24/2023, 2:01 PMinline etc, but it should work basically as-is)CLOVIS
07/24/2023, 2:01 PMRaise<Throwable>.catch(block: () -> T) would be a good addition to Arrow directly?simon.vergauwen
07/24/2023, 2:25 PMwithError? It's very similar to catch({ someMethodThatCanThrow(foo) }) { raise("Unkown") } imo, but we can consider it for sure ☺️
WithOkay, I see what you mean. That's exactly what you achieve with yourI don't have the Raise DSL, do I? We would like to use bothEither.catchas well as having a catch-all behaviour.ensure
boundary method. Might be interesting to consider something like that for Arrow.
inline fun <T : Throwable, Error, A> Either.Companion.catchAll(
handle: (throwable: T) -> Error,
block: @BuilderInference Raise<Error>.() -> A
): Either<Error, A> = fold(...)simon.vergauwen
07/24/2023, 2:27 PMcatch(block) { raise(handle(it)) }CLOVIS
07/24/2023, 2:39 PMRaise.catch was already part of Arrow, you're right, my version doesn't add anything useful.simon.vergauwen
07/24/2023, 2:39 PMThrowable and still needs the explicit handlerJan
07/24/2023, 2:43 PMcatch DSL is definitely good to know 👍 But yeah, we would like to avoid that repetition and prevent even accidentally forgetting it 😄
I would be honored to open a PR for catchAll if you are open to these kind of contributions ☺️simon.vergauwen
07/27/2023, 7:22 AMcatchAll or if we can get away with a different signature and catch.
We probably should do it for both Raise and Either. Let me know if I can help you with anythingJan
07/29/2023, 1:35 PMcatch in a non-breaking way. Also it might not be really obvious what the difference between catch and catchAll is supposed to be.
What would be the target branch for the PR? Then I'll check it out and see whats doable 🙂Jan
07/31/2023, 9:53 PMarrow-2 branch with adding overloads for either and Either.catch. It seems that both don't cause issues in tests, but somehow both feel a little bit odd: Either.catch "suddenly" has Raise capabilities when you specify another callback, and either now has two completely opposite behaviours: catch all or catch none 😕Jan
07/31/2023, 10:01 PMsimon.vergauwen
08/28/2023, 7:47 AM