aidanvii
08/19/2021, 1:59 PMResult
as a return type as of Kotlin 1.5. I’m having seemingly random crashes with suspending functions that return Result
(I haven’t checked with other inline/value classes). it’s happening in the generated invokeSuspend
:
Fatal Exception: java.lang.ClassCastException
java.util.ArrayList cannot be cast to kotlin.Result
I don’t have reliable repro steps for it, it seems to happen on some android devices, at different places but all the same crash, but not always 😢
I’m really stumped with it. I’ve been looking at the difference in the decompiled bytecode between suspending and non suspending functions that return Result
, I can see casting of some Object
to Result
, assuming that’s what’s failing 😕stojan
08/19/2021, 2:49 PMsuspend fun foo(): A
basically desugards to fun foo(): Result<A>
(it's a bit more complicated because of async stuff but it's the basic idea) this means it can fail with Throwable
or succeed with A
that means that suspend fun bar(): <Result<A>>
desugars to fun bar(): Result<Result<A>>
meaning it can: fail with Throwable
(outer result), fail with Throwable
or succeed with A
.
The recommended solution merge the two Throwable
failures and change the return type to ``suspend fun bar(): A``. You can then use runCatching
or try/catch
when launching your coroutine to handle the failureelizarov
08/19/2021, 3:20 PMaidanvii
08/19/2021, 3:30 PMrkeazor
08/20/2021, 7:12 AMaidanvii
08/21/2021, 11:38 AMResult
with a non inlined version until it's resolved. It's less hassle than unwrapping all return types. Ideally we could somehow force it not to be inlined until it's fixed. I'm using Jetpack Compose which seems to lag behind kotlin versions, so I imagine I'll need to wait a bit longer 🥲Result
APIrkeazor
08/21/2021, 2:50 PMaidanvii
08/21/2021, 4:46 PMrkeazor
08/22/2021, 1:42 AMaidanvii
08/22/2021, 6:35 AMsuspend
function that returns a Result
, but it has a parameter with a default value. removing the default value or removing the suspend
operator works (though in my case I can’t remove the suspend
)suspend fun main(args: Array<String>) {
getResult(true).onSuccess { println(it) } // A-OK
getResult().onSuccess { println(it) } // ClassCastException!
}
suspend fun getResult(arg: Boolean = true): Result<Boolean> = Result.success(arg)