I read somewhere that supporting `try-catch` insid...
# compose
y
I read somewhere that supporting
try-catch
inside composables was planned. Is that still being worked on? I'm trying to use Arrow's
Raise
with Compose and Molecule, which I guess makes it a doubly-niche use case.
s
Where would you be doing such a thing in composition and not inside an effect? Even in molecule and especially with arrow + raise I am having a hard time to see where you’d need to do a try/catch in composition
y
E.g. if I want to do a complicated filtering of values. Yes I can just use
Option
, but I'd like to instead have the ability to just do
raise(None)
. Sorry if it wasn't clear, but I mentioned
try-catch
because that's what
Raise
uses to function. I'm not directly using that, I'm instead `raise`ing inside an
option
block
s
I think I’d like to see some code for this because I still don’t see why you’d raise an error completely out of your molecule instead of handling it inside there and have the result of that be the output of your molecule.
y
This very basic example works for some reason:
Copy code
@Test
  fun filtering2() = runTest {
    lateinit var itemChannel : SendChannel<Int>
    val items = callbackFlow {
      itemChannel = this
      awaitClose()
    }
    val flow = moleculeFlow(RecompositionMode.Immediate) {
      option {
        val item by items.collectAsState(0)
        if (item == 2) raise(None) else item
      }
    }.filterIsInstance<Some<Int>>().map { it.value }
    flow.test(10.seconds) {
      awaitItem() shouldBe 0
      itemChannel.send(1)
      awaitItem() shouldBe 1
      itemChannel.send(2)
      itemChannel.send(3)
      awaitItem() shouldBe 3
      cancel()
    }
  }
However, when trying to extract the plumbing out of it, I get a `ComposeRuntimeError`:
Copy code
@Test
fun filtering2() = runTest {
  lateinit var itemChannel : SendChannel<Int>
  val items = callbackFlow {
    itemChannel = this
    awaitClose()
  }
  val flow = myMoleculeFlow {
    val item by items.collectAsState(0)
    if (item == 2) raise(None) else item
  }
  flow.test(10.seconds) {
    awaitItem() shouldBe 0
    itemChannel.send(1)
    awaitItem() shouldBe 1
    itemChannel.send(2)
    itemChannel.send(3)
    awaitItem() shouldBe 3
    cancel()
  }
}
inline fun <T> myMoleculeFlow(
  crossinline body: @Composable OptionRaise.() -> T
) = moleculeFlow(RecompositionMode.Immediate) {
  option {
    body()
  }
}.filterIsInstance<Some<T>>().map { it.value }
Seemingly, I can't ever catch an exception coming out of a composable, even if that composable is being inlined, but I can have exceptions inside a composable function? I'm not entirely sure how to achieve what I want here. I hope that at least the example makes sense: I want to achieve filtering
s
What you see as an annotation internally changes the shape of that lambda more than you may think (I've only read about it too, don't know details), but yeah I don't think they expect exceptions to be thrown out. But as you can see if you never throw an exception through a composable "scope" (if that makes any sense) maybe that should be fine
I still feel like you can surely do this without the exceptions through the composables right? 😅
y
I know compose does crazy things, I'm just surprised that
inline
doesn't play that nicely with it (my expectation would be that manually inlining an
inline
method shouldn't change whether the code works or not). I wonder if there's a "compose way" to do this.
s
I'm still not 100% sure what
this
is here when you say a compose way to do this. If you show like the real use case here you have with the existing code it might be much easier to discuss
y
The issue is that I'm creating something kind of abstract: I'm trying to create something akin to monad comprehensions. I'm thus trying to have an easy way of
filter
ing unwanted values.
s
If it's just to return null inside a molecule flow, you can just do that operation inline as normal Kotlin code, without a raise or whatever 🤷‍♂️
Yeah, and can that not happen inside the presenter itself? Or with a normal non-compose function which takes input and returns the filtered output back?
y
Yeah that's true, it just runs into the same issue though that Raise is intending to solve: I would have to explicitly pass on the
null
value from any other possibly-filtering function I callo > normal non-compose function which takes input and returns the filtered output back The issue is that I want to filter based on flows that were `collectAsState`ed. I want to be able to basically "cancel" a current composition if you will. Maybe that's the terminology I should be using. I want to cancel the current composition because it can't produce a useful value, and instead I'd like to wait until another state change causes a recomposition
s
"cancel a current recomposition", so do you want it to return nothing? Because that may be going against what compose wants to do in the first place. Instead of "cancelling" it shouldn't you just short circuit your calculation and return the "none" case, whatever that may be
y
Well exactly, I want to return a none case, but I either have to do that explicitly by wrapping in
Option
, which is inelegant, or with exceptions and
Raise
, which compose doesn't support easily
s
but why does the function that is an extension on
Raise
need to be a composable itself? And not a normal function?
y
That's... very true actually. I guess that function can either run its own molecule and expose that as a
Flow
, or it can be a Composable and return an
Option
. The annoying bit, I guess, is that both aren't possible at once, but I guess that's not that significant of a drawback
👍 1
p
Personally I prefer not using exceptions in the UI code. Makes the code not so appealing.
s
This was for molecule, so it wasn't UI code.
p
Ah sorry didn't go through the thread tbh, just so the headline and went straight to comment. I had seen code try/catching in Composable or view related code and wanted to express that is not good looking. I am pretty sure there are other opinions but in my case I would avoid any exception handling in Composable UI/View land
s
Yes, but again, this isn't about compose UI 😅
p
Sorry 😁
😄 1