Greeting! I was just reminded, that there are no d...
# arrow
o
Greeting! I was just reminded, that there are no different eager and suspend DSLs anymore. Unfortunately, I lost track of the latest innovations in Arrow and now I am confused. 🤔 There still is an Eager Effect, that "runs eagerly, and can be used in non-suspending code". Now, ChatGPT concluded that said effects "execute eagerly when possible, but will suspend when necessary to wait for results". Is that true? Essentially, I just want to know, if I need to use eagerEffect when my endpoints are not suspended and effect when I have a suspended entry-point, like when using webclient in a spring boot app. Will look into the new Spring Boot example (https://t.co/EHvN25jsbX), but needed to get this out, so I can focus on my task. Thank you very much.
s
Hey @Oliver Eisenbarth, Okay, so if you're working with
eagerEffect
and
effect
you still need to differentiate between the two starting from 1.2.0-RC.
But
either.eager { }
and
either { }
is no longer needed.
EagerEffect
and
Effect
are now
Raise<E>.() -> A
and
suspend Raise<E>.() -> A
. And they don't share a common ancestor, even though
EagerEffect
fits into the shape of
Effect
but not vice-versa. Ideally with context receivers you can completely avoid this and don't have to work with
Effect
or
EagerEffect
at all and just write.
Copy code
context(Raise<E>)
/* suspend */ fun myCode(): Int = 1
This gives much more natural interopt, and allows horizontal composition as well.
Copy code
context(Raise<String>, Raise<Error>)
/* suspend */ fun myCode(): Int = 1
You practically never have to return
Effect
unless you need to explicitly pass or cache lambdas. You can just
recover
,
fold
,
either
to calculate a terminal value.
Copy code
context(Raise<String>)
/* suspend */ fun myCode(): Int = 1

val either: Either<String, Int> =
  either { myCode() }

val recovered: Int =
  recover({ myCode() }) { -1 }
I am currently publishing the new docs with a lot more information on this regard. TL;DR we've removed the constraint of
suspend
and thus in some of the builders such as
either
,
option
, and
nullable
you don't have to distinct between the two anymore. That also allowed us to remove some other duplicated APIs etc from Arrow. https://arrow-kt.io/learn/quickstart/migration/
o
Thank you very much for clarification!
p
@simon.vergauwen I always wanted to ask, are you guys planning to start building some kind of experimental preview not-for-production version of arrow with context receivers already, using context receivers as we have them now? Or do we really have to wait couple of years until they are released and stable?
s
With this release there is not really a need to have a special experimental release. Everything should already work with context receivers perfectly. Considering that
context(Raise<E>) () -> A
and
Raise<E>.() -> A
are almost the same. This comment also touches upon it, https://kotlinlang.slack.com/archives/C0B9K7EP2/p1680600833107529?thread_ts=1680388003.721149&amp;cid=C0B9K7EP2 We also mention them already in a couple of sections of the documentation, since people that are opt-ing to the experimental support can benefit from all goodies in combination with Arrow. I really hope we get a more concrete idea of the timeline @ KotlinConf, and it won't be a couple years 😭 If you had some specific APIs are improvements in mind I'd love to hear it. I guess the biggest loss is that currently
option
and
result
have a different receiver/context type rather than just
Raise<None>
and
Raise<Throwable>
to project the DSL but that could be overcome with a tiny context receiver external library. Or could be overcome with a couple extension functions in a local project. That is something we could expose from arrow-kt.
p
Thanks, Simon! What I am interested the most actually is how is your personal experience with current context receivers? I would so much like to opt-in and use them already but don't know what to expect. All I've seen so far is couple of comments on reddit from people that it is all bad and they had to opt-out. But without anything concrete. Are there bogus random runtime errors? Incorrect or undefined behaviour? I can't find anywhere what exactly does "pre-release binaries that cannot be used in production code" mean... What is production? How does it know that it is in production? Will it blow up if it is in production? Will it make everything slower because it is not optimised or something?
s
Oh, that is a bit surprising. I've only encountered the opposite reactions but I am not much on reddit in relation to software.
Are there bogus random runtime errors? Incorrect or undefined behaviour?
No, the only thing I've encountered and others in this channel is that sometimes code unexpectedly doesn't compile. IDEA inserts an incorrect space in front of
context
keyword. But all code that is compiled works correctly as expected, since it's basically just a parameters so, similar to extension functions:
Copy code
context(TypeA)
fun example()
becomes
Copy code
public void example(TypeA context1)
Just like
Copy code
fun TypeA.example()
becomes
Copy code
public void example(TypeA receiver)
So there is nothing that can actually go wrong at runtime once it's compiled, and tested. I have some example projects where I have a context receiver branch: https://github.com/nomisRev/ktor-arrow-example/pull/35 https://github.com/47deg/gh-alerts-subscriptions-kotlin/pull/18 (need to merge main, and fix conflicts) And it all works fine, and passes the test-suite. I personally would dare to use them on a "production" project, but for a library I cannot because it forces downstream users to also opt-in. Hopefully we get good news at KotlinConf in terms of K2, and future roadmap/timeline and get this sooner than we expect 🤞 🤞