Is there a good explanation available of how the `...
# arrow
c
Is there a good explanation available of how the
bind
abstraction is implemented? I'd like to adapt it to a StateFlow (essentially the same as Either's with success and error, but the value changes over time).
s
Hey @CLOVIS, I am afraid it will not work for
Flow
since that requires multiple calls to
Continuation#resume
, we've tried many different ways and were never able to figure out an implementation for
Flow
. I've been trying to document as much of Arrow's design and there is quite a lot of information on the design for Arrow 2.x.x here, https://github.com/arrow-kt/arrow/pull/2797
c
Oh :/
s
The implementation has changed, and evolved a lot over time to make the internals lighter, faster and work in safer ways within Kotlin. There are some different approaches possible, and we had something that worked for multiple emissions but it was very delicate in it's use.
c
Maybe there's another way then, I'm using a type which is essentially
Flow<Either<AppError, T>>
and I'm trying to figure out a proper API so it's convenient to use... Do you have any recommendations/clues?
s
I think the most convenient way is to write an extension function like this:
Copy code
fun <E, A> Flow<Either<E, A>>.mapEither(transform: EffectScope<E>.(A) -> B): Flow<Either<E, B>> =
  map { original ->
     either<E, B> {
        transform(this, original.bind())
      }
   }
Pseudo example:
Copy code
val original: Flow<Either<AppError, String>> = TODO()

val mapped: Flow<Either<AppError, Int>> =
  original.mapEither { string ->
     ensureNotNull(string.toIntOrNull()) {
       AppError.ConversionFailed
     }
  }
So
mapEither
transparently gives you access to the entire
either { }
DSL.
c
Oh that's good
r
Also depends on semantics in a bit...maybe context receivers typed to errors and the Flow collector
Copy code
context(FlowCollector<A>, Raise<E>)
suspend fun foo(): B {
   emit(a)
   raise(e)
   return b
}
maybe it's possible to create a Flow subtype that types it's error and can be used as single receiver
s
That is also possible, and but only works for producing values not consuming them.
c
In the
@Composable
world with things like Molecule, do you think it's possible to get the same early-return behavior as with
either
? If I understand correctly
either
works using the internal
suspend
machinery, which I don't think
Composables
have 🤔
s
I’m not sure what you mean with that 🤔 In Kotlin Coroutines rely on exceptions (
Result<A>
), and you can make scoped cheap exceptions similar to GOTO mechanism. This is what is used in
Flow#take
for early-returns,
kotlinx.coroutines.Job
for cancellation and also for Arrow’s DSLs. I’m not familiar enough with
@Composeable
to give you a concrete example, or reply, but I’m not sure why it would not work 🤔 I think the biggest hurdle is that
@Composable
by-passes the type-system, no? Rather than
action: Composable.() -> A
c
Another issue is that to my knowledge, a
@Composable
function cannot
suspend
... I'll see what I can manage with Composables that return
Either
. I'm especially interested because unlike suspend functions, Composable functions do not transmit their exceptions cleanly up the call stack, so there's no alternative for error management
s
Composable functions do not transmit their exceptions cleanly up the call stack
Oof, that sounds tricky. In Arrow 2.x.x the
either { }
DSL will be
inline
, and there will be no more need for
suspend fun either { }
or
either.eager { }
I am not sure if that would improve the situation? I can look into fixing the publishing of Arrow 2.x.x SNAPSHOT if you’d like to give that a try.
c
Oh that sounds good. How will you implement
bind
if you're not guaranteed to be in a suspending context?
I'm currently having many dependency issues with Compose so I'm not planning on trying any other pre-release lib 😅 I'll do with the stable Either for now, it's already much better than what I had
s
I’m not sure what you mean with that 🤔 In Kotlin Coroutines rely on exceptions (
Result<A>
), and you can make scoped cheap exceptions similar to GOTO mechanism.
This is what is used in
Flow#take
for early-returns,
kotlinx.coroutines.Job
for cancellation and also for Arrow’s DSLs.
But here you can check all the implementation details, and the design discussion 🙂 Any, and all, feedback is very welcome! https://github.com/arrow-kt/arrow/pull/2797