Alejandro Serrano.Mena
12/18/2025, 9:10 AMOlaf Gottschalk
12/19/2025, 6:49 AMensureNotNull where @IgnoreableReturnValue is missing, though! 😉Olaf Gottschalk
12/19/2025, 6:52 AMpackage arrow.core.raise.context - I am talking about the Raise context extensions.Olaf Gottschalk
12/19/2025, 6:59 AMmapOrAccumulate or zipOrAccumulate in conjunction with verification and collection of errors. So the functions I call all return Unit. Of course the mapped/zipped result of such a call is irrelevant, because it's just List<Unit> or Unit . With the new return value checker, those two functions also require the return value to be used. Is there any way to make an exception if the result is just Unit? Or does Arrow have specific functions I didn't find yet that do the accumulation part without actually mapping/zipping?Olaf Gottschalk
12/19/2025, 7:02 AMpublic inline fun <Error, A, B> Raise<NonEmptyList<Error>>.mapOrAccumulate( is still missing in Raise context extensions... 😉Olaf Gottschalk
12/19/2025, 7:06 AM@RaiseDSL
context(raise: Raise<NonEmptyList<Error>>)
inline fun <Error, A, B> mapOrAccumulate(
nonEmptyList: NonEmptyList<A>,
@BuilderInference transform: RaiseAccumulate<Error>.(A) -> B,
): NonEmptyList<B> {
contract { callsInPlace(transform, AT_LEAST_ONCE) }
return raise.mapOrAccumulate(nonEmptyList, transform)
}
@RaiseDSL
context(raise: Raise<NonEmptyList<Error>>)
inline fun <Error, A> mapOrAccumulate(
nonEmptyList: NonEmptyList<A>,
@BuilderInference transform: RaiseAccumulate<Error>.(A) -> Unit,
) {
contract { callsInPlace(transform, AT_LEAST_ONCE) }
val _ = raise.mapOrAccumulate(nonEmptyList, transform)
}Alejandro Serrano.Mena
12/19/2025, 9:33 AMensureNotNull, it should be added, definitely
about the mapOrAccumulate and similar, two points:
1. the Kotlin team is working on some way of saying "ignore the value if the function I pass is ignorable", but it's not there yet
2. for the time being, you should use forEachAccumulating if you don't care about the valuesOlaf Gottschalk
12/19/2025, 9:49 AMzipOrAccumulate which is necessary when the functions that could raise errors are not uniform. Let's say I have some validators that are able to raise Nel<String> as an error. I then call them using:
context(Raise<Nel<Error>>)
fun validateA() {}
context(Raise<Nel<Error>>)
fun validateB() {}
zipOrAccumulate(
{ validateA() },
{ validateB() }
) { _, _, -> }
By the way: I always wondered why there is no RaiseNel type, equivalent to EitherNel?Alejandro Serrano.Mena
12/19/2025, 12:25 PMRaise, then you should get Unit back, which is implicitly ignorable
• if you're using Either, then you get a Either<Nel<Error>, Unit> back, and then the warning is correct: you should do something with that valueOlaf Gottschalk
12/19/2025, 12:26 PMOlaf Gottschalk
12/19/2025, 12:27 PMzipOrAccumulate is basically the accumulate part of it. There's nothing to zip because everything is just Unit.Olaf Gottschalk
12/19/2025, 12:30 PMzipOrAccumulate, I need this:
accumulate {
accumulating { action1() }
accumulating { action2() }
accumulating { action3() }
accumulating { action4() }
accumulating { action5() }
}
But without the experimental raise accumulate stuff and tbh I am rather confused about the two similarly named functions stacked within each other. Why is one called accumulate and the other accumulating?Alejandro Serrano.Mena
12/19/2025, 12:31 PMaction1 accumulating errors"Alejandro Serrano.Mena
12/19/2025, 12:32 PMaccumulate {
action1().bindOrAccumulate()
action2().bindOrAccumulate()
...
}Olaf Gottschalk
12/19/2025, 2:24 PMYoussef Shoaib [MOD]
12/26/2025, 3:19 PMaccumulate and accumulating is not perfect, I agree. The intuition is that accumulate is your entry point into the Accumulate DSL, while accumulating is part of the Accumulate DSL, and is used to "soften" errors.
The basic structure of accumulate and accumulating will continue to work. In fact, there's no intention to remove this DSL at all. The exact design and semantics may change, however.
Basically, if it shows up in a non-experimental inline function, we guarantee binary compatibility for it. Source compatibility, not so much, because the DSL is evolving.
However, the source pattern of
accumulate {
accumulating { ... }
accumulating { ... }
accumulating { ... }
}
is incredibly unlikely to change. It's the core of the Accumulate dsl, and that DSL is something we want to ship fully eventually.
Worst case scenario, maybe we change the names to be more understandable, but there's always be some accumulate {} equivalent and some accumulating { } equivalent