The "high-level concurrency" says "Using typed err...
# arrow
c
The "high-level concurrency" says "Using typed errors with KotlinX Flow is prone to leaking the
raise
DSL scope and should be used carefully. More information can be found in the typed errors documentation." The typed errors documentation never mentions flows, however… What does it mean? I'm stuck on a
delay
in a
channelFlow
that never completes, maybe this is the origin of the problem?
m
@CLOVIS I might be wrong.. but it might be related to the ability to build something a bit weird like so
Copy code
val eitherFlow: Either<String, Flow<Int>> = either {
  flow { 
    emit(1)
    emit(2)

    raise("failed") // leak
    
    emit(3) 
  }
}
which in terms cancellation, that will only manifest when the flow is executed, so that raise will leak.. as can be seen when trying to materialize the flow.
Copy code
suspend fun main() {
  eitherFlow.map { flow -> flow.toList() }
}

// Exception in thread "main" arrow.core.raise.RaiseLeakedException: raise or bind was called outside of its DSL scope, and the DSL Scoped operator was leaked
// This is kind of usage is incorrect, make sure all calls to raise or bind occur within the lifecycle of effect { }, either { } or similar builders.
I really doubt there’s any way to make that fail on compilation, but if there’s one I’d be really interested!
c
There's a specific exception for leaked raises? 😯 The team really thought of everything
There is a way: (ab)use DslMarker to create a DSL in which Raise can't be called, then provide a
context(Raise<*>) fun flow(context(NoRaise) block: FlowEmitter<T>.() -> Unit)
Not perfect because you have to override the flow builder, and it's quite a lot of stuff to add, but it works
y
Hopefully at some point we'll have a mechanism in Kotlin to prevent values from escaping a local scope, and then this issue could be solved accordingly. I don't know what that could look like though, although I've had some ideas that it could work similar to lambda params of `inline fun`s