Hello. Is there any design reason for Either.flatM...
# arrow
y
Hello. Is there any design reason for Either.flatMap and Either.map not being inline anymore (it was inline in 0.8.2 and it isn't in 0.10.0)? It has become unfriendly to suspending functions after that.
And if it was a design decision, what alternatives do we have now?
p
Either.catch { }
inside the
flatMap
, and changing the
map
to
flatMap
the design decision is that suspended functions are impure, so allowing them on those position was an unintended side-effect of trying to be cute about performance using inline
👍 1
I hope it’s not too much a hassle to fix it
y
Sorry, perhaps I misunderstood you, but Either.catch is also a suspend function, so I can't use it inside the flatMap
r
This is the same issue we discussed earlier in the other thread
You need IO
to injest the suspended effects
IO<Either<E, A>>
y
Oh,
It all connects, of course.
And again, sorry if I'm making too much noise.
Managed to re-do the call stack using IO and it's not complaining about the semantics anymore.
My problem now is that I can't build, because once I introduce
arrow-fx
gradle throws this out:
Copy code
Supertypes of the following classes cannot be resolved. Please make sure you have the required dependencies in the classpath:
    class arrow.typeclasses.MonadContinuation, unresolved supertypes: arrow.core.Continuation
arrow-fx is 0.10.0 and it fails to build with arrow-core 0.8.2 and 0.10.0
I also have
"arrow-extras-extensions", "0.9.0"
Alright, I finally wen to the top of the mountain and saw the light of the sages' staff. This has been an enlightening day, thanks for such a great library.
I'm ussing arrow-effects
p
wtf
that build error
how was it fixed?
r
You only need 'arrow-fx' v 0.10.0 if you are starting something new with IO
y
It was not fixed at all. I didn't need arrow-fx, but arrow-effects.
It seems that fx obscures arrow.core.Continuation, it's in arrow.typeclasses.Continuation if I reference arrow-fx
Just having both projects in the classpath causes the crash.
Cosa mala.
Lucky for me, as @raulraja mentioned, I don't need the package.
Today was a busy day, but if they are intended to work together, I'll open an issue tomorrow.
I'll try to reproduce in an empty project
r
Thanks that will be great , that should not happen and we don't need our continuation wrapper
y
Hey, your contributing guidelines do not specify anything about bug reports? I guess is just details of the problem and steps to reproduce?
r
I realize now you are mixing versions of arrow. That is probably the reason
Need to get rid of all the 0.9.0 stuff
Either.fx is in arrow-core
y
Oh, then I just could not find the namespace for fx
So... if I want do do IO and also have the fx bindings for either, which packages should I use to be up to the latest version?
r
arrow-core and arrow-fx
y
Right, thanks. I think I got that almost there.
Managed to have the whole underlying layer to return a IO that defers the whole thing, and the integration tests seem to agree that it works.
r
Awesome 🙌
y
Yeah, but now I'm blocked at the edge of the world.
It's a ktor endpoint, and inside unsafeRunAsync, I can't execute call.respond, because it needs a corroutine context.
I'll figure it out myself at some point, perhaps I'll pester you a bit more.
But that will be in the future, I'm calling this a victory and moving on for a while.
r
y
That is indeed interesting, will go over that.
Hello again! Decided to spend a bit more time on this. I've checked your example, and in there you are doing a runBlocking.
The ultimate issue I had is that I can't run it async. Blocking runs fine.
The problem is that call.respond is a suspend function, so I can't call it inside the unsafeRunAsync.
p
yes, you're trying to do ugly side-effects in a subscription block
😮 1
what you want is to continue flatMapping
Copy code
val program = paymentHandler.createPaymentIntent(initializePaymentRequestDto, user) // This returns an IO
IO.fx {
  val wt = !program.attempt()
  val result = wt.fold( { Left(Conflict()) }, { inner -> inner })
  !result.fold({ IO.effect { call.respond(InternalServerError) } }, { IO.effect { call.respond(OK, initializePaymentResponseDto) } })
}.unsafeRunAsync { }
y
Gosh.
OK, I'm going to try that. You should really grow a long white mustache at this point.
message has been deleted
p
hahaha thanks!
y
This is a step forward, definitively.
But...
message has been deleted
Wait wait.
I think I figured it.
p
IO.effect
🙂
y
Yes, but it falls short, sadly.
The endpoint keeps returning a null.
Feels like the call.responds are being called in another thread.
p
what's the callback?
if you have it, then
IO.async
and follow the types
y
OK, will do that after lunch.
Thanks for you immense patience.
👍🏼 1
p
no prob, cheers 😄
y
OK, so call.respond is what should be called inside the callback.
OK, it seems like I'm missing something important. I've been trying to build the callback outside the fx, so then I can do IO.Async inside but all approaches I take lead me to the same road: I can't run call.respond without a coroutine context.
I swear I'm trying like my life depends on it.
If I understood you correctly, the idea would be to have the callback in the coroutine context of the route, and then call it with IO.async(callback) inside the fx block.
The badrequest on line 49 works like a charm, but all the ones I'm using inside the
effect
blocks return a null.
If I run it with unsafeRunSync it works, too, but that kind of defeats the purpose of using coroutines.
p
holy lack of type hints batman hahaha
let's do one thing
fun Route.paymentRoutes() {
please annotate the type there
this method is synchronous and blocking...is it like at entry point, the main for your request?
y
Yes, it is.
p
does
post
accept suspend functions?
y
paymentRoutes is Unit
p
my point is that you need to surface things a bit more, rather than doing operations at the leaves
y
It doesn't.
p
val ioResult: IO<Something> = resolveUser().fold({ }, {})
it should,
call.respond(BadRequest)
is suspend
y
Oh, I meant that if routes could be a suspend fun.
I misunderstood the question.
p
but what I'm seeing here, you aren't using IO for anything...changing threads or any operators
so, IO should be used when you need to do one of those things, cancellation, races, threading, some form of concurrency
if you only have suspend functions calling each other it shouldn't be necessary
y
And what about not blocking threads?
p
and when you have an entry point that's suspend, like
post { HERE }
is
you do
myIo.suspended()
to unpack it
in that snippet you aren't using threads anywhere
oh
paymentHandler.createPaymentIntent(initializePaymentRequestDto, user)
okay, hear me out
y
Yes.
p
paymentHandler.createPaymentIntent(initializePaymentRequestDto, user).suspended()
and don't use the fx block below
so no effects, no unsaferunasync, no nothing
you're just unpacking IO using
suspended
y
program: IO<Either<Error, InitializePaymentResponseDto>> = paymentHandler.createPaymentIntent(initializePaymentRequestDto, user)
p
program.suspended()
y
OK.
That might be in the latest version.
p
yes
0.10
y
Of arrow
OK, then I release your soul from my terrible influence.
p
that should simplify all your code
y
I will try with the latest version later in the week
Thanks a lot.
p
yay success!!