https://kotlinlang.org logo
Channels
100daysofcode
100daysofkotlin
100daysofkotlin-2021
advent-of-code
aem
ai
alexa
algeria
algolialibraries
amsterdam
android
android-architecture
android-databinding
android-studio
androidgithubprojects
androidthings
androidx
androidx-xprocessing
anime
anko
announcements
apollo-kotlin
appintro
arabic
argentina
arkenv
arksemdevteam
armenia
arrow
arrow-contributors
arrow-meta
ass
atlanta
atm17
atrium
austin
australia
austria
awesome-kotlin
ballast
bangladesh
barcelona
bayarea
bazel
beepiz-libraries
belgium
benchmarks
berlin
big-data
books
boston
brazil
brikk
budapest
build
build-tools
bulgaria
bydgoszcz
cambodia
canada
carrat
carrat-dev
carrat-feed
chicago
chile
china
chucker
cincinnati-user-group
cli
clikt
cloudfoundry
cn
cobalt
code-coverage
codeforces
codemash-precompiler
codereview
codingame
codingconventions
coimbatore
collaborations
colombia
colorado
communities
competitive-programming
competitivecoding
compiler
compose
compose-android
compose-desktop
compose-hiring
compose-ios
compose-mp
compose-ui-showcase
compose-wear
compose-web
confetti
connect-audit-events
corda
cork
coroutines
couchbase
coursera
croatia
cryptography
cscenter-course-2016
cucumber-bdd
cyprus
czech
dagger
data2viz
databinding
datascience
dckotlin
debugging
decompose
decouple
denmark
deprecated
detekt
detekt-hint
dev-core
dfw
docs-revamped
dokka
domain-driven-design
doodle
dsl
dublin
dutch
eap
eclipse
ecuador
edinburgh
education
effective-kotlin
effectivekotlin
emacs
embedded-kotlin
estatik
event21-community-content
events
exposed
failgood
fb-internal-demo
feed
firebase
flow
fluid-libraries
forkhandles
forum
fosdem
fp-in-kotlin
framework-elide
freenode
french
fritz2
fuchsia
functional
funktionale
gamedev
ge-kotlin
general-advice
georgia
geospatial
german-lang
getting-started
github-workflows-kt
glance
godot-kotlin
google-io
gradle
graphic
graphkool
graphql
graphql-kotlin
graviton-browser
greece
grpc
gsoc
gui
hackathons
hacktoberfest
hamburg
hamkrest
helios
helsinki
hexagon
hibernate
hikari-cp
hire-me
hiring
hongkong
hoplite
http4k
hungary
hyderabad
image-processing
india
indonesia
inkremental
intellij
intellij-plugins
intellij-tricks
internships
introduce-yourself
io
ios
iran
israel
istanbulcoders
italian
jackson-kotlin
jadx
japanese
jasync-sql
java-to-kotlin-refactoring
javadevelopers
javafx
javalin
javascript
jdbi
jhipster-kotlin
jobsworldwide
jpa
jshdq
juul-libraries
jvm-ir-backend-feedback
jxadapter
k2-early-adopters
kaal
kafka
kakao
kalasim
kapt
karachi
karg
karlsruhe
kash_shell
kaskade
kbuild
kdbc
kgen-doc-tools
kgraphql
kinta
klaxon
klock
kloudformation
kmdc
kmm-español
kmongo
knbt
knote
koalaql
koans
kobalt
kobweb
kodein
kodex
kohesive
koin
koin-dev
komapper
kondor-json
kong
kontent
kontributors
korau
korean
korge
korim
korio
korlibs
korte
kotest
kotest-contributors
kotless
kotlick
kotlin-asia
kotlin-beam
kotlin-by-example
kotlin-csv
kotlin-data-storage
kotlin-foundation
kotlin-fuel
kotlin-in-action
kotlin-inject
kotlin-latam
kotlin-logging
kotlin-multiplatform-contest
kotlin-mumbai
kotlin-native
kotlin-pakistan
kotlin-plugin
kotlin-pune
kotlin-roadmap
kotlin-samples
kotlin-sap
kotlin-serbia
kotlin-spark
kotlin-szeged
kotlin-website
kotlinacademy
kotlinbot
kotlinconf
kotlindl
kotlinforbeginners
kotlingforbeginners
kotlinlondon
kotlinmad
kotlinprogrammers
kotlinsu
kotlintest
kotlintest-devs
kotlintlv
kotlinultimatechallenge
kotlinx-datetime
kotlinx-files
kotlinx-html
kotrix
kotson
kovenant
kprompt
kraph
krawler
kroto-plus
ksp
ktcc
ktfmt
ktlint
ktor
ktp
kubed
kug-leads
kug-torino
kvision
kweb
lambdaworld_cadiz
lanark
language-evolution
language-proposals
latvia
leakcanary
leedskotlinusergroup
lets-have-fun
libgdx
libkgd
library-development
lincheck
linkeddata
lithuania
london
losangeles
lottie
love
lychee
macedonia
machinelearningbawas
madrid
malaysia
mathematics
meetkotlin
memes
meta
metro-detroit
mexico
miami
micronaut
minnesota
minutest
mirror
mockk
moko
moldova
monsterpuzzle
montreal
moonbean
morocco
motionlayout
mpapt
mu
multiplatform
mumbai
munich
mvikotlin
mvrx
myndocs-oauth2-server
naming
navigation-architecture-component
nepal
new-mexico
new-zealand
newname
nigeria
nodejs
norway
npm-publish
nyc
oceania
ohio-kotlin-users
oldenburg
oolong
opensource
orbit-mvi
osgi
otpisani
package-search
pakistan
panamá
pattern-matching
pbandk
pdx
peru
philippines
phoenix
pinoy
pocketgitclient
polish
popkorn
portugal
practical-functional-programming
proguard
prozis-android-backup
pyhsikal
python
python-contributors
quasar
random
re
react
reaktive
realm
realworldkotlin
reductor
reduks
redux
redux-kotlin
refactoring-to-kotlin
reflect
refreshversions
reports
result
rethink
revolver
rhein-main
rocksdb
romania
room
rpi-pico
rsocket
russian
russian_feed
russian-kotlinasfirst
rx
rxjava
san-diego
science
scotland
scrcast
scrimage
script
scripting
seattle
serialization
server
sg-user-group
singapore
skia-wasm-interop-temp
skrape-it
slovak
snake
sofl-user-group
southafrica
spacemacs
spain
spanish
speaking
spek
spin
splitties
spotify-mobius
spring
spring-security
squarelibraries
stackoverflow
stacks
stayhungrystayfoolish
stdlib
stlouis
strife-discord-lib
strikt
students
stuttgart
sudan
swagger-gradle-codegen
swarm
sweden
swing
swiss-user-group
switzerland
talking-kotlin
tallinn
tampa
teamcity
tegal
tempe
tensorflow
terminal
test
testing
testtestest
texas
tgbotapi
thailand
tornadofx
touchlab-tools
training
tricity-kotlin-user-group
trójmiasto
truth
tunisia
turkey
turkiye
twitter-feed
uae
udacityindia
uk
ukrainian
uniflow
unkonf
uruguay
utah
uuid
vancouver
vankotlin
vertx
videos
vienna
vietnam
vim
vkug
vuejs
web-mpp
webassembly
webrtc
wimix_sentry
wwdc
zircon
Powered by
Title
s

Satyam Agarwal

01/17/2023, 5:36 PM
Hei ! I noticed that Arrow has deprecated few apis in 1.1.5 that was released. I understand that you want to limit the surface of the api. But the library have some great methods now being being deprecated. Without having more context or read Proposals in 2.0.0 roadmap, I think the idea is to be more align with what kotlin standard libraries provide and recommend ? Take
filterOrElse
for example. Me and few in my team are fan of function chains. we feel each function denotes what kind of transformation is being applied to the passed data. deprecating such functions force us to push conditions in flatmap or use bind. Looks like we will have to eventually start using either block even for small programs. My question really is, that as library provider, is there a huge overhead for Arrow in maintaining such util functions on the data types like Either and Option ?
r

raulraja

01/17/2023, 5:50 PM
Hi Satyam, there is no huge overhead but rather trying to align with the essence of what we think can do best in Kotlin's and little more. We are actually trying to get further than removing the
indirect
methods when context receivers are stable in kotlin. In that case you would be able to declare programs with
context(Raise<String>)
fun foo(): Int = raise("oops")
Entirely eliminating the need to have either blocks or function chains. Just regular code that raises typed values where required. This doesn't mean Either will disappear or that things like
filterOrElse
may make sense for convenience or not. What we do not want to do is maintain a large library of combinators for indirect function style because in Kotlin we don't need to with suspension and things like context receivers, bind or either blocks. Either will become one of the target types you can evaluate a program that uses the
context(Raise<A>)
.
As for
filterOrElse
and other API's you don't think that should be deprecated. Do you have an example on how you are using it and how it compares to an
either
block? Thanks for the feedback!
s

Satyam Agarwal

01/17/2023, 7:05 PM
I understand. I am not saying that such indirect functions should not be deprecated. Nothing that can’t be accommodated by using different methods like raise, shift, flatmaps etc. Been using the library since 0.6.0, and have been adapting to the different patterns introduced since then by the library. So, there is an obvious shift I have to adapt again, specifically around context receivers, and the new patterns arrow library is bringing by being more inline with kotlin. Just had to ask to understand the thought process of the maintainers, have seen this library come a long way 😊 :arrow: ❤️
r

raulraja

01/17/2023, 8:38 PM
Still for cases where
either + bind
or context receivers turns out more verbose we think it's fine to keep the additional operations. We did our best to think about each case but maybe we missed a few where it makes sense to preserve and that is possible. Ideally we don't end up with a big API but we can evaluate every operator on a case by case basis and decide with the community if any should remain before 2.0. from the deprecated ones.
s

Satyam Agarwal

01/18/2023, 6:45 AM
For sure. We do use either blocks where we have many side effects and the order we need to use the evaluated values is not too down. And when operations naturally falls in top down order we use function chains. So we haven’t seen that either blocks become bloated. And even if they do, usually it indicates code smell, and we extract operations to a new method.
But when writing function chains, such methods are just convenience. Zip, product, float map, tap, flatTap, filterOrElse, filterOrOther, handleWithError have made stepping through and reading through chains read so easy.
s

simon.vergauwen

01/18/2023, 7:48 AM
Only
filterOrElse
and
filterOrOther
are deprecated? 🤔 The other ones you mentioned are staying, or where renamed to more Kotlin Std naming. I.e. we had a vote on
tap
and
tapLeft
and those got renamed to
onRight
and
onLeft
.
You can find some more rationale, and discussions here. https://github.com/arrow-kt/arrow/pull/2830 If there is something that you and your team find really lacking, please open a ticket on Github with your use-case and we can discuss there to keep it for 2.0.0 A secondary reason for doing deprecations now, is so that we can gather feedback. We tried to ask for as much feedback as possible before releasing 1.1.5 through Slack and Twitter.
o

Olaf Gottschalk

01/18/2023, 8:56 AM
I felt exactly the same. The deprecated function like leftIfNull on Either and such make my code a LOT more unreadable and full of noise characters for ?: , .? right / left and flatMaps. I doubt this will make things easier to comprehend and force me to write my own extension functions again making this easy to read. So Arrow removes such functions and many people write exactly the same helper extension functions... sad...
I fully understand that getOrElse can replace getOrHandle of course, that really is a nobrainer and can be exchanged. But the speaking functions are hard and will be missed.
s

simon.vergauwen

01/18/2023, 8:58 AM
Hey @Olaf Gottschalk, Not sure if you saw my reply on your comment in the PR. This deprecations were not made with
flatMap
and
?
in mind, to the contrary. If this API is in such high demand, we can always keep it around. We've asked for feedback in many places, and only got positive reactions before this release.
o

Olaf Gottschalk

01/18/2023, 9:01 AM
Sorry Simon, did not see it yet. 🙂 Well, what did you have in mind then? I mean, I updated to 1.1.5 and had like 40 deprecation warnings of exactly that kind. And the quick fix offered for leftIfNull is a flatMap with b?.right() ?: default().left - so you apply that. Is there a better way to express that? If so, would it be possible to put that into the ReplaceWith statement? What would you recommend?
I hurt even more for rightIfNotNull and some others because the function chaining gets lost...
s

simon.vergauwen

01/18/2023, 9:03 AM
We consider the following code to be Arrow & Kotlin idiomatic. It leverages both the Arrow DSL, and Kotlin smart casting to offer an elegant and Kotlin idiomatic API.
either {
  val b: B? = bind()
  ensureNotNull(b) { default() }
  // b is smart-casted to non-null
}
Sadly
ReplaceWith
doesn't allow this kind of deprecations 😞
This works for all kind of
null
based code, and also exists for predicate
ensure(predicate) { }
without requiring
right
or
left
. It also works on a function method basis.
suspend fun EffectScope<MyError>.checkSomething(): Unit =
  ensure(predicate) { MyError }
o

Olaf Gottschalk

01/18/2023, 9:04 AM
I've used the either DSL but found it rather bloated if I could have done it with a simple function chaining... maybe a personal preference? Also, either DSL makes me go back to code blocks - which I try to avoid almost everywhere in favor of expressions
Also, this bind() function inside a DSL... many of my not-so-functional colleagues don't understand it at all... 😉
Maybe this is also a good chance to ask you directly: what is the performance hit going to use suspend functions instead of flatMap and alike?
s

simon.vergauwen

01/18/2023, 9:08 AM
Also, either DSL makes me go back to code blocks - which I try to avoid almost everywhere in favor of expressions
We've had to opposite experience, and same for everyone we received feedback from prior to merging this PR. Your non-functional colleagues find
flatMap
more idiomatic than
bind
? 🤯 That's the first time I ever heard that. Similarly for code blocks, rather than FP based chaining. DSL blocks are equivalent to what
suspend
does for concurrency. You can however completely avoid
bind
if you want by using context based code, as shown above with the extension function. Context receivers will open the door to this even more.
what is the performance hit going to use suspend functions instead of flatMap and alike?
None, using
flatMap
is actually slower.
o

Olaf Gottschalk

01/18/2023, 9:10 AM
Interesting... I really need to get more into discussions here. Yes, explaining people what map and flatMap do is somehow easier than explaining a DSL and a function bind() in my experience...
Also, many of my colleagues rarely see suspend functions and might not really understand the concepts. Because here in FP in Arrow it is just a vehicle and not for asynchronous work - which confuses them a lot...
But what is your opinion regarding functions as expressions and going back to code blocks?
I always got a simile when a function is just an expression
s

simon.vergauwen

01/18/2023, 9:12 AM
There is also a non-suspend version of this DSL, but in reality Kotlin Coroutines doesn't apply concurrency. It's just a mechanism the compiler provides. The most popular, or best known, use-case is concurrency but both are unrelated.
o

Olaf Gottschalk

01/18/2023, 9:13 AM
I know that.. 😉 It's less experienced programmers that get problems when they see "suspend" and don't understand why....
s

simon.vergauwen

01/18/2023, 9:13 AM
In FP people typically spit code as much as possible, and most functions are simple expressions. I also love them. The DSL provides an alternative to Scala's for-comprehensions or Haskells do-notation. In both those languages
flatMap
is also not really loved and the languages offer these alternatives to avoid them.
So comparing Scala to Kotlin.
for {
 a <- produceA()
 b <- produceB()
} yield a + b
in Kotlin (consider you can even get rid of
bind
here as well).
either {
  produceA().bind() + produceB().bind()
}
Another big + of this Kotlin encoding is that it allows you to mix effects, where in Scala and Haskell you need monad transformers to combine
IO
(or
Future
) with
Either
.
o

Olaf Gottschalk

01/18/2023, 9:16 AM
So, here as an example, I had this:
Either.catch {
how can I switch off Enter sending.... AAAAH
Either.catch {
    // some legacy code that can produce null and throw exceptions
}.mapLeft {
    // turn the Throwable to an error object
}.leftIfNotNull {
    MissingBlahError()
}
now has to be
...
.flatMap { it?.right() ?: MissingIDocTypeField.left() }
if I want to use your either { } approach, I immediately have to make my fun suspend and this essentially forces me to make every function suspend. What I dislike about this, to be honest, is: formerly when I saw a suspend fun I immediately knew that this function does something that takes time, might suspend, etc. So I really rely on these indications by function signatures. I think it makes things easy to grasp. Now many more functions will have to turn suspend even though they use suspend for something completely different. So I essentially lose expressiveness....
s

simon.vergauwen

01/18/2023, 9:34 AM
There is also
either.eager { }
which doesn't require suspension.
o

Olaf Gottschalk

01/18/2023, 9:34 AM
is using either.eager giving me a performance penalty?
If one does that in all situations?
s

simon.vergauwen

01/18/2023, 9:35 AM
There is no performance penalty for the DSLs, they're much faster than chaining functions like that.
o

Olaf Gottschalk

01/18/2023, 9:35 AM
that's totally crazy - but cool. Maybe that is something to express more?
s

simon.vergauwen

01/18/2023, 9:36 AM
They still use Kotlin Coroutines under the hood, but without allowing concurrency. So all optimisation from the Kotlin compiler are still in place. Similar to
Sequence
from Kotlin Std. The documentation is due an overhaul/improvement, but it's something we've planned as part of the 2.0 work.
o

Olaf Gottschalk

01/18/2023, 9:38 AM
Do you have an advice in my either DSL block? So first, I use
ensureNotNull
for my check of null - but then I need to call legacy code with catch. Should I use
Either.catch { ... }.bind()
directly?
Oups. bind is deprecated?
Ah, ok. bind is also a function of Either... and that is deprecated. Sorry.
s

simon.vergauwen

01/18/2023, 9:43 AM
You can do a couple things, use
bind
like you show there. Directly calling
Either.catch
in the
either.eager { }
block, or extracting it to a separate function.
fun myFunction(): Either<Throwable, A> =
  Either.catch { ... }

either.eager {
  myFunction().bind()
  Either.catch { ... }.bind()
}
Ah, ok. bind is also a function of Either... and that is deprecated. Sorry.
I think that was an extension on
Either<Throwable, A>
only but it was deprecated a couple versions ago since it leaked from the
Result
DSL and was unsafe.
o

Olaf Gottschalk

01/18/2023, 9:44 AM
Yep. My problem was the left type had to be mapped first before calling bind. Otherwise the compiler chose the "wrong" bind of Either
wouldn't it also be cool to have something like a catch function (similar to ensure) inside the EffectScope?
So to avoid using Either.catch again?
s

simon.vergauwen

01/18/2023, 9:49 AM
Yes, we have one prototyped but it's not yet been released. It has kind-of a funky signature but it supports all use-cases. Similar to
Flow#catch
. So it allows you to transform an error to a new error, but also provide a fallback value.
fun sideEffect(): Int = ...

either.eager {
  val i = catch(
    { sideEffect() }
   ) { t: Throwable ->
    // otherFunction(throwable).bind()
    // shift(MyError(throwable))
    fallback
  }
  ...
}
Using
shift
, and these DSLs you can avoid using
right()
,
left()
or
bind()
, etc everywhere. Basically removing all allocations from working with
Either
and monads. Since this can also be mixed with KotlinX Coroutines if you use the
suspend
version of
either { }
.
o

Olaf Gottschalk

01/18/2023, 9:51 AM
So the performance gain basically comes from less allocations of objects?
s

simon.vergauwen

01/18/2023, 9:54 AM
Both from avoiding allocations, and from the super efficient way the Kotlin compiler optimises Coroutines.
flatMap
requires 2 allocations, while
either.eager
only requires a single one. Within
either.eager
you can however call an infinite amount of
flatMap
without requiring additional allocations. So the benefit also depends on the code, but even in a small snippet
either.eager
is theoretically faster.
o

Olaf Gottschalk

01/18/2023, 9:55 AM
So, you said that I can avoid using left right or bind - but the bind inside the either DSL is not something to avoid, you mean "the other bind()", right?
s

simon.vergauwen

01/18/2023, 9:58 AM
These two functions are equivalent, but note that only 1 requires
bind
and
left()
.
fun EagerEffectScope<MyError>.x(): Int =
  shift(MyError)

fun y(): Either<MyError, Int> =
  MyError.left()

either.eager {
  x() + y().bind()
}
(For 2.0 we're considering flattening
EagerEffectScope
and
EffectScope
into
Raise
, or renaming to
EagerRaise
and
Raise
) With Kotlin's context receivers you can "free" the extension receiver by moving it to the context.
context(EagerEffectScope<MyError>)
fun x(): Int = shift(MyError)
o

Olaf Gottschalk

01/18/2023, 9:59 AM
That's cool! I also can't wait to finally get ContextReceivers...
So by using the scope and shift's all that is left is the correct type instead of Either wrappers - and that does not require any bind... understood
s

simon.vergauwen

01/18/2023, 10:02 AM
And all utilities should be available through elegant DSL syntax, that are available for all types not just
Either
. So the same DSL is applicable everywhere, even for your own types that you might want to integrate to the DSL. This way you can also move, and combine different types inside the same DSL without having to move back -and forth between types.
o

Olaf Gottschalk

01/18/2023, 1:39 PM
@simon.vergauwen you already made me understand some things much better - I have another problem with Validations and the pattern to accumulate errors instead of failing fast. I reach the limit of 10 parameters to use zip - and I ask myself: is there also a better "DSL" way of doing that? In my case it's about config validation with a "Thing" that requires 10 parameters to be correct, all of them packed in a ValidatedNel which I then zip to call the constructor of that thing. a.zip(b, c, d, e, ... ::Thing) to construct the Thing... now there's yet one more parameter and the zip is not available for more than 10 things. Any other/better/more FP way to do this?
s

simon.vergauwen

01/18/2023, 1:41 PM
Hey @Olaf Gottschalk, Glad I was able to provide help ☺️ Be sure to ask any question here if you have any other doubts! Yes, this is also a common problem 😞 We plan to also explain this clearly in the docs. We choose 9 parameters as the upper limit of what we encode in Arrow but you can quite easily compose/nest multiple
zip
within each-other. Here is my answer on SO to this question 😉 https://stackoverflow.com/questions/72782045/arrow-validation-more-then-10-fields/72782420#72782420
o

Olaf Gottschalk

01/18/2023, 1:50 PM
Yeah, I learned about this Slack through JetBrains' Advent of Code channel... should have done this earlier. I am now starting to revisit all my former flatMap / left / right situations... Thanks a lot for your very kind help!
s

simon.vergauwen

01/18/2023, 1:51 PM
My pleasure ☺️
o

Olaf Gottschalk

01/19/2023, 8:15 AM
Morning @simon.vergauwen - I got another question. When dealing with the either effect scope of R and the thing to bind has a different left type A, this needs to be changed prior to bind() to fit into the scope. So, naturally one could do
val x = myFun().mapLeft { mapAToR(it) } .bind()
. But I also found out I could do this:
val x = attempt { myFun().bind() } catch { shift(mapAToR(it)) }
Which one would be preferred? I assume the first one would allocate at least one more Either wrapper which the second one does not?
s

simon.vergauwen

01/19/2023, 8:37 AM
Good morning @Olaf Gottschalk, There is not really a "preferred", Arrow still aims to facilitate both writing styles. Otherwise it would eliminate one over the other, as Kotlin Std often does. I.e. many people might prefer splitting into
fun res(): Either<E, A> = myFun().mapLeft { mapAToR(it) }
with
res().bind()
over the second one. Even though the second one can also be split,
fun EagerEffectScope<E>.res(): A = attempt { myFun().bind() } catch { shift(mapAToR(it)) }
. The second one is an higher abstraction on top of Coroutines, so the implementation is re-used for
Option
,
Ior
,
Result
and other custom types.
assume the first one would allocate at least one more Either wrapper which the second one does not?
That is correct, but that is often neglect-able in the face of network or database interactions. Arrow tries to be somewhat opinionated, but also not so much that it limits the user in how they model their code. If you're already heavily using
Either
than the first option is absolutely fine, but the second one opens the door to leverage context receivers more in the future. Note that these APIs are still a bit in flux until context receivers are completely stable, so they might change name or shape if needed.
o

Olaf Gottschalk

01/19/2023, 9:02 AM
That's great yeah. Just through this discussion my whole mindmap on Either types has now broadend to see that fun EffectScope<A>.doThis(): B is equivalent to fun doThis(): Either<A, B> but much higher abstracted because it's neither bound to Either nor uses memory objects to transport the fact that the computation might fail indicated by type A... that's awesome. For ValidatedNels with accumulating errors there is no such abstraction, right? We are stuck to using zip / valid / invalid functions?
s

simon.vergauwen

01/19/2023, 9:08 AM
Yes, exactly 🙌
For ValidatedNels with accumulating errors there is no such abstraction, right? We are stuck to using zip / valid / invalid functions?
We're working on this towards 2.0, I hope to include the new APIs in 1.2.0. We're thinking of flattening
Validated
into
Either
by exposing its accumulating errors APIs for
Either
, and exposing the same APIs over
EffectScope
. In the same fashion as our discussions above. Some references to see the on-going work. https://github.com/arrow-kt/arrow/pull/2892 https://github.com/arrow-kt/arrow/pull/2880 https://github.com/arrow-kt/arrow/pull/2795
j

Jarkko Miettinen

01/23/2023, 11:25 AM
What we do not want to do is maintain a large library of combinators for indirect function style because in Kotlin we don't need to with suspension and things like context receivers, bind or either blocks.
Where could I learn more about what other bigger changes are in the books? Say, for the 2.0.0. This PR was good list for some of the API changes. I am trying to get some idea on how stable the library is.
s

simon.vergauwen

01/23/2023, 11:28 AM
The library is stable in terms of functionality, but there is a some redundancy in the APIs which is what we're removing. Besides that, some other changes are simple renames to be more aligned with Kotlin Std naming. Or simplifications to the APIs, and encodings.
From 1.x.x -> 2.x.x that PR you shared is the most impactful, together with https://github.com/arrow-kt/arrow/pull/2795.
j

Jarkko Miettinen

01/23/2023, 5:34 PM
Thanks! I got a bit over 100 different deprecation warnings for upgrading one of our services. Most of these point us towards using effect scope and ultimately result in general the same level of readability. For stability I was thinking more on the current users code continuing to work as-is even at the cost to maintainer (more code, less elegant interfaces, etc). But this, I think, is more of a question of general approach the library takes into maintenance.
s

simon.vergauwen

01/24/2023, 8:46 AM
Maintainability of downstream projects is one of our most important priorities. We regularly ask for feedback in this channel, both on the topic of maintenance as renaming or improving current APIs. The Either API improvements for exampel were a community based discussions. Some of the renames, which can be refactored automatically through IntelliJ, were feedback input from the community and not arbitrary things the maintainers decided to do. "towards using effect scope", if this is the deprecation I have in mind a simple
find + replace
can fix all of them without breaking anything. So it's non-impactful. Which seemed like a non-impactful refactor for downstream projects. We've always included these steps in the migration guides of the release posts. https://www.47deg.com/blog/arrow-v1-01-0-release/#the-effect-runtime-2 APIs and binary will be stable in the 1.x.x, and nothing will be breaking until 2.x.x which means that you can safely rely on any 1.x.x based library without any runtime conflicts or upgrading your current codebase. We don't expect any more changes like this after 2.x.x, since we've ironed out all these improvements and API renaming together with the community in the last 3 years of 1.x.x being stable.
j

Jarkko Miettinen

01/25/2023, 1:42 PM
Hey, that's good to hear! My concern isn't about the amount of work needed for, say, these changes any such changes but more about the philosophy on how the library is developed. And your message helps with that. "Philosophy" being here where the library stands in the tongue-in-cheek continuum of:

Rich Hickey

<----> JavaScript Library on making breaking changes to existing API.