Let's say you have a algorithm function that acts ...
# arrow
o
Let's say you have a algorithm function that acts like a pure function. This algorithm takes alot of time to compute, and thus adding suspend is normally recommended. However, in arrow world, suspend means that the function causes side effects, while this function doesn't at all (it is still pure, just takes alot of time). What should one do here?
s
IMO, Arrow is not changing the definition of
suspend
, it is just cleverly piggybacking on the functionality
suspend
provide naturally, which is a huge convenience for arrow.
suspend
is isomorphic to
IO<A>
, and thus not only allowing catching side-effects smartly, but also making it lazy.
🔝 5
However, for your case from version
0.12.0
, you can just wrap your method with
withContext(IO)
{ yourBlock() }`
And return a pure result.
o
But then the function gets a suspend signature right? And becomes "tagged" as "produces side effects"
s
arrow-fx-coroutines
library provides
either
block that handle both
suspend () -> A
, and
suspend () -> Either<Throwable, A>
interchangeably.
o
So what do you suggest the function's signature to be?
s
But then the function gets a suspend signature right? And becomes “tagged” as “produces side effects”
That is not entirely true. afaik, you would need to return
Either<Throwable, A>
, if your function has side affects. But you can just return
A
in your case. f.eks. :
Copy code
suspend fun myIOPureFun(): A {
    return withContext(IO) {
        myHeavyComputations()
    }
}
eventually at the edge of the world you entry must be wrapped in
either { ... }
block. in case something blows up, and you were “sure” that function was pure.
o
The docs say that the only requirement for a function to be marked as it may cause side-effects, is that if it has suspend in it. I can't find a source saying that it also needs to return Either<Throwable, A>.
In Arrow Fx, we use suspend fun to denote a function that may cause side effects when invoked.
In the example below, println(a : Any): Unit is a side effect because, every time it's invoked, it causes observable effects by interacting with the System.out stream and signals that it produces no useful output by returning Unit.
s
sure. that is my taste to carry errors along the execution. But you need to see this example : https://arrow-kt.io/docs/fx/#executing-effectful-programs
Copy code
fun main() { // The edge of our world
  val env = Environment()
  env.unsafeRunSync { greet() }
}
this is basically wrapping your method with
either { … }
but you can avoid
Either
datatype entirely. Its upto you how you want to do error handling.
o
I don't think Either does say anything about a function causing side effects. A function that returns Either can still cause side effects
s
Then you have a leak, afaik. Either is specifically designed to contain all side effects.
o
I think you are confusing side effects with throwing exceptions. Either is mostly used for functions to indicate that it can error in a pure way, without throwing exceptions. But it does not say anything about, let's say, a network call
Which is a side effect
s
I may have not explained good enough 😅 I am still a noob.
no no, I am not mixing them, from my knowledge, a side effect is anything that may return a different result given a same argument, again and again.
to avoid this, we use eithers.
o
No, either just says that a function can return two different types, that's all actually
☝️ 1
s
in a pure function, you can replace it with the result if same argument is given.
o
Either just says, I can be A or B
Nothing else
s
hmm, I am sorry, I think I need to call big guns here as I can’t explain properly 🙂 cc: @raulraja / @simon.vergauwen
j
Throwing an exception is a side-effect, because a side-effect is any behavior or result not represented by a function's return type. In other words, anything that makes a function not representationally transparent. Wrapping in an either block transforms such a side-effectful function into a non-side-effectful one by returning Either.
👍 1
o
Throwing an exception is a side effect, but not all side effects are exceptions being thrown. I can throw no exceptions, but can still make network calls and will still make it a side effectfuk function. Either doesn't do anything here.
👍 1
j
How would you make network calls and guarantee there'll be no exceptions? What about network-down or HTTP exceptions?
If you know there'll be no exceptions thrown by your function, then a suspend function is all you would need. No need for Either.
s
@Orhan Tozan
This algorithm takes alot of time to compute, and thus adding suspend is normally recommended
Where is this being recommended?
suspend
is designed to wrap callback-based code. You could use suspend to offload the long-running work on a separate thread, and then finish in a callback-based manner. @Satyam Agarwal
That is not entirely true. afaik, you would need to return 
Either<Throwable, A>
, if  your function has side affects.
This is not the case, there is no need to introduce
Either<Throwable, A>
since
suspend
already implies
Throwable
.
Then you have a leak, afaik. Either is specifically designed to contain all side effects.
This is actually not the case at all 😅
Either
is simply meant to model a branching or a union. It represents a value with one of two possible types. Whilst suspend models
Throwable | A
or
Result<A>
. However, it doens't expose the
Throwable
on the value level only at a semantic level. Which means you cannot call
suspend
from normal code but only from other
suspend
code. In addition to some other properties which make it the equivalent of
IO
, for example it being lazy. It however is a good pratice to type errors, wheter it is
Either<Throwable, A>
or
Either<MyError, A>
where
MyError
is a
data class
,
sealed class
or
enum class
.
👍 1
No, either just says that a function can return two different types, that's all actually
This is 100% correct. If your function is impure, wrapping it in
Either
will not make it pure. In those cases you want to make it with
suspend
to make it lazy.
o
@simon.vergauwen thanks, so what do you recommend my algorithm's function signature to be?
s
Well, there are a couple of options depending on your needs/use-case. It can simply be
fun algorithm(): Result
, which models the concerns correctly. A caller of this functions can then offload it to an
IO
thread to prevent it from hogging a computation thread.
withContext(<http://Dispatchers.IO|Dispatchers.IO>) { algorithm() }
This however makes the caller
suspend
to call
withContext
. If you'd want to enforce your users from calling the algorithm on a background thread, only then would I introduce
suspend
in the function signature of
algorithm
.
👍 1
Here is an interesting source on pools, and which pool to use for what. https://gist.github.com/djspiewak/46b543800958cf61af6efa8e072bfd5c