Olaf Gottschalk
02/20/2023, 8:28 PMsimon.vergauwen
02/20/2023, 8:33 PMValidated
vs Either
, and the result was that most were in favor of exposing Validated
behavior on top of Either
.
It’s probably the most tedious refactoring 😞, and I am currently looking into OpenRewrite to see how we can automate it.
Some resources if you’re interested:
• 2.0.0 Remove Validated
• Raise.zipOrAccumulate
• Either.zipOrAccumulate
• Iterable.mapOrAccumulate
• Iterable.flattenOrAccumulateOlaf Gottschalk
02/20/2023, 8:38 PMsimon.vergauwen
02/20/2023, 8:42 PMEither
and Validated
are both definitely the biggest changes 😅
The DSL has been around since 1.x.x and has now been renamed to Raise
, and the API is getting some new DSLs but nothing is removed or changed beside the name.
We do publish release posts for ever stable release announcing new features, and documenting all changes and migration guide if anything has been deprecated.simon.vergauwen
02/20/2023, 8:44 PMValidated
vs Either
.
We hope to release the 1.2.x in 2-3 weeks with automated migration for Validated
-> Either
and EffectScope
-> Raise
. Everything will be lengthly explained in the release post, which will be shared here, and in the Github release. After that all non-deprecated code will be source -and binary compatible with 2.0.Olaf Gottschalk
02/20/2023, 8:47 PMOlaf Gottschalk
02/20/2023, 8:50 PMsimon.vergauwen
02/20/2023, 8:51 PM1.1.6-alpha.28
which is a stable version on maven central, it’ll become 1.2.0 but we haven’t bumped the automatic versioning yet.Olaf Gottschalk
02/20/2023, 9:12 PMsimon.vergauwen
02/20/2023, 10:27 PM"error".invalidNel()
and it’s being replaced to "error".toEitherNel()
? 🤔 that should indeed be leftNel()
instead.
I will review the API tomorrow, thanks for sharing 👍Sam Painter
02/21/2023, 5:26 AMOlaf Gottschalk
02/21/2023, 7:06 AMleftNel()
but that does not exist. I first used nel().left()
which is so long and then just found toEitherNel()
. In the 1.1.6-alpha.28
I am now using, Validated
is not yet deprecated, so there are no replace with helpers, too. I just did not know why this toEitherNel()
exists.
I would not even ship this function as "error".toEitherNel()
says nothing at all - it feels just wrong.Olaf Gottschalk
02/21/2023, 7:11 AM.valid()
and .invalid()
somehow... It looked much better before, even though I appreciate that now Either
"does it all". Maybe I would write delegation methods with these names again if possible.Olaf Gottschalk
02/21/2023, 7:14 AM.flatMap { ... }
now always becomes .recover { raise(...) }
? If I know I want to change the error type, is there still a "flatMappy" way to express that? I somehow dislike typing more and repeat myself with recover-raise plus the extra parentheses....simon.vergauwen
02/21/2023, 8:48 AMEitherNel<E, A>
is just a typealias
of Either<NonEmptyList<E>, A>
. There are no more HKT, or typeclasses, but simple Kotlin code.
Arrow exposes the different behaviours through concrete APIs, rather than generic APIs with different typeclass instances.
The point of merging Validated
and Either
was too avoid having multiple implementations that have the same meaning, but rather have a couple of functions that implement the desired functionality.simon.vergauwen
02/21/2023, 8:52 AMtoEitherNel
doesn't sound great at all. I will review the APIs, and tag you in the PR if you don't mind.
a former🤔now always becomes.flatMap { ... }
?.recover { raise(...) }
flatMap
stays flatMap
, or becomes bind
but flatMap
is not removed.
recover
replaces handleErrorWith
& handleError
, and both are replaced with recover { fe(it).bind() }
and recover { fe(it) }
. This API is inspired by Flow.catch, and it covers much more signatures then the former two methods since you have access to the entirety of the Raise
DSL inside recover
.
You can recover from Either<E, A>
to Either<E2, A>
, so you can also turn that into Nothing
if the error has been resolved and a fallback value has effectively been returned. I.e.
val original: Either<String, Int> = "fail".left()
val fallback: Either<Nothing, Int> = original.recover { 1 }
simon.vergauwen
02/21/2023, 8:56 AMraise
perse, you can also use bind()
, ensure
, etc. but it depends a bit on your surrounding code. It introduces an additional bind
in the case of handleErrorWith
, but it results in a singular more powerful API that can cover all cases and is even future proof with context(Raise<E>)
when the time comes.
object Error
object MyError
val a: Either<Error, Int> = MyError.left()
fun fallback(error: Error): Either<MyError, Int> =
MyError.left()
a.recover { fallback(it).bind() }
Olaf Gottschalk
02/21/2023, 9:44 AMOlaf Gottschalk
02/21/2023, 10:54 AM