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.catch
as 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