Hello. Is it feasible to do a binding for Either t...
# arrow
y
Hello. Is it feasible to do a binding for Either that does not provide its own coroutine context? I'm working with a library that is not friendly to be enclosed in the binding because of that.
r
Hi Yeray, do you have a small example where Either.fx is not working for you? The binding for Fx should not require a suspension runtime to work
It just restricts suspension to ensure you don’t place nested suspended context that could go async inside its body.
y
Oh... yes, I'm using the old api, I'll give it a shot with fx.
Funny thing, next on my playlist is jorge castillo's talk on fx.
Hi, I'm hitting the same problem using fx: I'm consuming a library (Exposed) that creates its database transactions in a restricted coroutine scope.
I'm digging in the library to find the point where it is defined.
Restricted suspending functions can only invoke member or extension suspending functions on their restricted coroutine scope
I'm digging in the library right now to find the point where it is defined. (we have it wrapped and our code would be of no value)
Or perhaps I'm missing something else.
r
Normally Either is not on the outside of an effect but inside it
If you wrap effects that can go async or whatever Either would have to block nested async processes to obtain a value and that would be no good for your application.
y
I have a series of effects that can fail, they are divided in: - Calling our payment provider. - Storing data related to the payments.
I was trying to explain it and I just ended up repeating the design flaw you pointed out.
r
Looks like what you really need is IO
And in some cases you can have IO<Either, CustomError, A>>
The IO around it will give you the means to inject foreign restricted context via effect { }
If you have a reduced example we can help translating to IO
y
Oh,,,
I was just going to thank you for this and you just went twice as cool.
The problem is that we wrapped Exposed with a library on our own.
To add resiliency, circuit breakers...
And... rollback, which is the core of the problem.
So if anything goes left or none in the context, the whole transaction rolls back. Which is good when you are saving several entities related, not good if our payment provider tells us that the user has a stolen credit card and we roll back the attempt.
And we can't isolate the transactions in the same flow because of the restricted thing.
Perhaps IO will solve it.
I'll give it a shot.
(all of this was to explain that a reduced exampled might be more complex than one might expect)
r
IO should solve it
Since IO can wrap anything even when concurrent or async
y
With the
effect
wrap around it.
No?
r
yes… for example:
Copy code
suspend fun foo(): Unit
val program: IO<Unit> = IO.effect { foo() }
val attemptedProgram: IO<Either<Throwable, Unit>> = program.attempt()
program.unsafeRunAsync { eitherThrowableOrUnit -> ... } // edge of the world
IO is always lazy and will allow you to compose a program you on ly run at the edges
nothing happens until you cal unsafeRunAsync because
program
is lazy and a value you can pass around wherever you need
y
OK, thanks a lot, will try to have this working tomorrow.
Hi again, sorry to keep pestering you. I seem to be blocked by one last thing.
It really looks like IO is what I needed.
And I can provide a code sample now.
Copy code
val getInvoice: suspend () -> Either<Error, InvoiceDto> =
            suspend {
                database.transactionReadError {
                    invoiceRepository.getInvoiceForUser(initializePaymentRequestDto.invoiceNumber, user)
                }
            }
        fun program(): IO<Either<Error, InvoiceDto>> =
            IO.fx<Either<Error, InvoiceDto>> {
                effect { getInvoice() }
            }
I want to execute several functions like
getInvoice
and they all can fail.
The point is to do it in a binding fashion.
And... I think I got it, I had to give my slow head another twist. You have been ridiculously helpful.
Thanks a lot.
Question is: This does require my code to fail with throwables?
r
An IO action as any function in the JVM may always fail throwing an exception so IO encapsulates that known fact so you can recover from it even if it came from an async context where try/catch would be useless.
When that happens Either will become rather useless in IO based apps since IO will bake in the Either effect
Also functions in the shape like yours where you have suspend Either E A, Will be automatically injested by effect moving the Left value to the Error type automatically further eliminating boilerplate
y
Oh boy.
Thanks a lot.
r
There is an issue with your code
You need to call !effect
To actually run it otherwise it's just suspended in a value
! Is Monad bind which will translate that bind into flatmap chains behind the scenes
That is how you achieve the imperative syntax you want to denote the order of your operations that you were mentioning earlier
y
Owch, thanks.