Hi, I am new to arrow. I have been using kotlin fo...
# arrow
d
Hi, I am new to arrow. I have been using kotlin for Android development and i wanted to explore arrow. So far I am a bit confused by many overlapping apis, there seem to be multiple ways to do the same thing and it is not clear to me how things should be used. Example IO { ... } vs IO.async().async { ... }.unsafeRunSync() vs IO.async().run { fx.async {ย ... }.fix().attempt().unsafeWhateverRun() }
s
IO
is getting deprecated, but those 3 are all the same API.
Since you're always calling it directly on
IO
.
d
what does it mean for IO to be deprecated ?
r
Hi Davide, IO has been replaced by the arrow Fx Coroutines lib which uses suspend functions instead of IO, it's faster and less verbose. https://arrow-kt.io/docs/fx/async/
d
ok that also explains why I was puzzled reading different sources
thx
r
We are changing the docs to reflect this before 1.0 and remove all references to IO in the next milestone release.
d
It was Sunday, i made the mistake of watching youtube videos... ๐Ÿ˜„
so reading https://arrow-kt.io/docs/fx/ - I capture this idea where basically by wrapping effects in suspend functions then "everything remains pure and isolated", until you actually execute it. I do not understand the value of this idea. I mean any program is pure if you don't execute it, and a suspend function can be pure as well. (related

https://youtu.be/uyqqoooKpmI?t=818โ–พ

)
๐Ÿ‘ 1
๐Ÿง 1
b
@Davide Bertola In my mind, the value comes in two parts: 1. (old syntax) Given a function
fun getHomepage(url: URI): IO<Homepage>
that is pure internally (that is, does not depend on global state or mutate global state), this is a pure function that generates a "program" or an "effect" that retrieves the homepage for a site. It's possible to execute this program (with .unsafeRunSync, etc.), but it is also possible to compose this program with any other program (
IO<Homepage>.flatMap(IO<B>).flatMap(IO<C>)
, etc. If we just have
fun getHomepage(url: URI): Homepage
it may not be possible to compose that with other functions/programs if it depends on or mutates global state. 2. Tied into the above is the idea of whether a given function is total (that is, has defined outputs for all inputs) or not. A well-written function
(URI) -> IO<Homepage>
is total: it is going to return an
IO<Homepage>
no matter what
URI
it is given, so it is very easy to reason about how to compose that together with other functions. A function
(URI) -> Homepage
is not total - for example, it may throw an exception while retrieving the homepage - and is very difficult to reason about, relatively speaking, because everything that has to interact with it has to take into account every possible error that occurs, in addition to dealing with the returned
Homepage
on success.
IO
- or whatever the suspend replacement is for it - ensures totality for both the success path as well as all error paths so the program execution is well-defined for all inputs.
๐Ÿ‘Œ๐Ÿฝ 1
In my (limited) experience with Arrrow (and Scala/Cats), the applications I have written using both methods have been much cleaner and had more well-defined behavior than the plain Java/Kotlin/Scala applications I had written in the past. It's hard for me to actually quantify, but I feel like the discipline required to write total functions would pay off in speed of development and reduced defects if I could develop entirely within a functional framework consistently
๐Ÿ‘๐Ÿฝ 1
d
I understand, but I am not questioning functional programming in general, at all. It's just that webpage that sets me off
โ€ข fun hi(): Unit = println("impure") โ€ข suspend pureHi() = { hi() }
first one is impure, but i refused to declare it as
suspend
, so i do not get the "benefit of the compiler checking"
second one is "pure" (?) and i can still declare it
suspend
so the compiler will check "as if it had side effects"
j
@Davide Bertola
any program is pure if you don't execute it
I think there's a contradiction here. A program's purity is defined by its behavior when executed. So if what keeps it "pure" is only not executing it, it can't be pure.
d
ok ๐Ÿ™‚
it does not have many side-effects though ๐Ÿ˜„
j
๐Ÿคฃ
But, by not having effects or side-effects, it also may as well not exist! A waste of effort!
@Davide Bertola I find it useful to think of functional programs as programs that, when executed, return other programs. This allows the first set to be pure but return, for the second set, impure programs that have side-effects when run.
It's the FP version of having your cake and eating it too!
A program that is (let's call it) fake-pure, only because it's not executed, cannot be composed with other programs in the way a real-pure program that returns an impure program can.
b
@Davide Bertola Ahh, I think I see.
suspend (URI) -> Homepage
is the same as
(URI) -> IO<Homepage>
via the use of compiler plugins. Consistent usage of the
suspend
function within a context (
IO
,
Either<L, _>
, etc.) is checked by the plugin, if I understand it correctly.
Under the covers, Scala's
IO
is just a thunk/suspend function. Arrow's current design just happens to eliminate the need to specify the datatype on the return value everywhere.
And I think that means it is actually closer to tagless final that way - specifying some arbitrary
F
with minimum requirements instead of
IO
Hopefully @raulraja or @simon.vergauwen or @pakoito will correct what I have wrong ^^ up there ๐Ÿ˜„
r
suspend functions are functions as such pure until applied. Application of a suspend function required another suspend context which means is pure until you use a runner at the edge. It's equivalent to IO and you can pass the program as values in the same way. Suspend functions is what IO looks like when the compiler knows about it and it's not modeled as a user data type. Suspend is closer to tagless final because the compiler knows about suspend functions. IO is an ADT and custom free monad style encoding. Suspend functions can be passed as values too.
@Bob Glamm I think your description is accurate
But our plugins play no role here. It's the actual Kotlin compiler. The fx Coroutines lib builds on the standard library intrinsics. Also arrow Continuations builds on that
d
suspend fun boo() = 1
@raulraja is this pure ?
r
Yes
Or at least as pure as IO<A> since it can be passed as value and manipulated in the same way
When you choose to run it at the edge is when effects take place and the compiler desugars into callback. If we did not have suspend the equivalent is nested fllatMaps
Also that function in non suspend is also pure because given always no args it returns the same output.
d
ok so in that dumb function, the idea of having it "checked by the compiler so you do not do something impure in your pure environment" is of no help
r
yes that function as suspend makes no sense since there is no suspension points or effects being applied inside and could just be non-suspend.
but the nice thing is that even in that case the compiler creates more efficient bytecode for it in contrast with using IO<A> where you get all the indirection penalty.
m
@raulraja @simon.vergauwen are there some app examples of using fx without IO?
r
@Marko Novakovic https://arrow-kt.io/docs/fx/async/ there is a few there and we are currently working on improving those docs
m
@raulraja thank you very much
๐Ÿ‘ 1