I just watched <@U0RM4EPC7> in the latest JetBrain...
# arrow
o
I just watched @simon.vergauwen in the latest JetBrains video about resource handling with Arrow. Cool video, thanks! One thing that again caught me by surprise: you used Either<Nel<String>, ...> for error accumulation along with a function called zipOrAccumulate. I have not heard of that before - I am always using Validations in these situations, ValidatedNel to be precise. Is this going to be removed in favor of Either?
s
Thank you, glad you liked it! There was a poll some time ago if people wanted to keep
Validated
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 ValidatedRaise.zipOrAccumulateEither.zipOrAccumulateIterable.mapOrAccumulateIterable.flattenOrAccumulate
o
Wow, thanks. Is there an "easy" way to get infos like this without stumbling over it by accident...? 😉 I mean like searching explicitly what is going to be changed in upcoming versions? I just try to teach everybody in my team to do proper validations and, yes, I had a hard time explaining the "differences" between Eithers and Validateds, but seeing this is going to be dropped anyhow I will probably stop teaching until it's there... 😄
s
Hmm, we don’t have anything on upcoming stuff but to be honest it’s kind of a unusual period in the last 6-ish months since we started investigating changes for arrow 2.0 and back-porting them 🤔 We’ve been just been gathering all experiences and community feedback from last 2-3 years of Arrow 1.x.x.. The changes we’ve discussed the other time around
Either
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.
Glad to hear you’ve had the same experience with explaining
Validated
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.
o
I guess especially for newcomers who now go on arrow-kt.io and read into the possibilities e.g. in the great "Functional error handling" tutorial it will definitely be somewhat frustrating to see things go soon. I mean, I am adventurous and like news and changes... but I know how others struggle sometimes. Maybe one should look into already hinting at these changes in the Tutorials. Anyhow, I am always watching all videos and try to find all blog posts and immediately want to change my project to be up to date asap... the only thing I cannot do for production is go to 2.0.0 snapshot yet... sadly.
But a few weeks until I can go there sounds really good. Will use the time to invest into SuspendApp and resource handling. Btw: I had developed my very own lib function for catching SIGTERM and gracefully stopping and releasing things. Great stuff!
s
Yes, I am quite sad with the current state of the docs… but it’s sadly all a matter of prioritising. Docs are quite time-expensive to invest, and it often ends up at the bottom of the backlog since no1 wants to spend spare time doing that 😅 We’re finally working on it, and revamping the website to be more user friendly. I’ll try to get that publicly released with 1.2.0 in couple weeks 😜 You could rely on
1.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.
o
When porting to EitherNel, I found this one: my former .invalidNel() calls can now be replaced by .toEitherNel() which I personally find rather low in expressiveness. I liked the clear "invalid" portion here. Unfortunately, there's no official leftNel(). If toEitherNel() is really "a thing", then shoudn't .toEither() be the equivalent .left() - just without the Nel part? Hmm...
s
To clarify, you previously had
"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 👍
s
As far as implementation for Validation -> Either are there just separate implementations for ‘Either<Nel, B>’ vs ‘Either<A, B>’ to handle accumulation vs short circuiting? I know Arrow used to use a HKT emulation where Either would have a Monad instance but I think Validation just has an Applicative instance.
o
@simon.vergauwen correct. I wanted to directly use
leftNel()
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.
In the face of my real validation code, I really did not enjoy removing all my
.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.
One more question - because of the Raise capability, a former
.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....
s
@Sam Painter no there is no 2 separate implementations.
EitherNel<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.
@Olaf Gottschalk I agree,
toEitherNel
doesn't sound great at all. I will review the APIs, and tag you in the PR if you don't mind.
a former
.flatMap { ... }
now always becomes
.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.
Copy code
val original: Either<String, Int> = "fail".left()
val fallback: Either<Nothing, Int> = original.recover { 1 }
You also don't have to use
raise
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.
Copy code
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() }
o
@simon.vergauwen great, please tag me, yes. I should really get into contributing to Arrow, I think. Maybe I can help myself, need to get into contributing!
@simon.vergauwen wow, you already found my first issue for Arrow 😉