Rajar
10/31/2022, 11:09 AMsuspend and not a non-suspend one ? If possible it could be an annotation where the ensuring would happen.
My use case is:
suspend fun <T> execute(request: suspend () -> T): T {
// code here
}
...
//code using 'execute'
execute(mySuspendLambda) // OK
execute { 1+1 } // warning or errorRajar
10/31/2022, 11:11 AMrequest::reflect.isSuspend but I want to check that at compile time and not runtime. And this lib is not a small one.Joffrey
10/31/2022, 11:26 AMsuspend function really suspendsRajar
10/31/2022, 11:47 AMsuspend { myLambda() }. In fact in a refactorization of our API interface we forgot to add the suspend key word in some methods which are not testable in our dev environment.
We got some Retrofit runtime error for one method testable in dev env (luckily!)
So I would like to ensure that it won't happen again with such compile check. If someone workaround the execute method with the suspend conversion, it's fine. But I wondered if it is possible to have such a strict check of a suspend or non suspend lambda :)streetsofboston
10/31/2022, 12:19 PM{ 1+someBlockingFunction() } is exactly the same as suspend { 1+someBlockingFunction() }.
If the lambda's code does or must suspend at some point in time, then it calls 'suspend' code and the lambda itself must be declared as 'suspend'.
Eg this is not possible: { 1+someSuspendFuntion() } and it must be suspend { 1+someSuspendFuntion() }.Rajar
10/31/2022, 1:19 PMrequest: suspend () -> T is a simple () -> T ?streetsofboston
10/31/2022, 1:27 PMrequest or not, but I'm not sure what you are trying to solve.
Even if a suspend lambda was passed to request , it still can contain (just) blocking (and non-suspending) code, which can never be cancelled.streetsofboston
10/31/2022, 1:30 PMrequest must be able to be cancelled, it must be able to call other suspend functions and that can only happen if the passed value/lambda is declared as suspend as well.Rajar
10/31/2022, 1:46 PMexecute { ... /* non suspend like 1 + 1 */ ... } and execute { ... delay(100) ... } are both allowed now . In this 2nd example AS/IDEA show a ⏸️ icon in the left column specifically on the delay part (I was wondering how it is done). I think I will pass on this enforcement for now, thank for your time 👍Kevin Del Castillo
10/31/2022, 2:03 PMIO dispatcher), so even if you wanted calls to suspend functions nothing forbids someone to do the following with your 1+1 example:
suspend fun onePlusOne() = withContext(<http://Dispatchers.IO|Dispatchers.IO>) { 1 + 1 }
suspend fun execute<T>(request: suspend () -> T): T {
// ...
}
execute(mySuspendLambda) // OK
execute { onePlusOne() } // OK? but still running "blocking" code, on a different contextJoffrey
10/31/2022, 2:48 PMIn fact in a refactorization of our API interface we forgot to add theThen I think what you should try to fix instead is to make those functions testable, and testedkey word in some methods which are not testable in our dev environment.suspend
streetsofboston
10/31/2022, 2:51 PM{ 1 + 1 } to the execute function's request parameter, the request parameter still gets a suspend lambda! The compiler just wraps it inside a suspend lambdastreetsofboston
10/31/2022, 2:51 PM{ 1 + 1} just becomes suspend { passedLambda.invoke() }..... (where passedLambda is { 1 + 1})Rajar
10/31/2022, 2:53 PMThen I think what you should try to fix instead is to make those functions testable, and testedYep, a way to do so would be to ensure each
@POST/@GET/etc. method is a suspend one though a test.Kevin Del Castillo
10/31/2022, 2:57 PMexecute function expects to run IO operations (such as network calls) you can also switch the context with withContext(<http://Dispatchers.IO|Dispatchers.IO>) so that execute is main thread safestreetsofboston
10/31/2022, 3:02 PMwhere you actually execute your suspend functionYup. Coroutines can not cancel blocking code.
Joffrey
10/31/2022, 3:04 PMrunInterruptibleKevin Del Castillo
10/31/2022, 3:05 PMrunInterruptible is wrapping the code in a suspend function, hence creating a suspend point where Kotlin can cancel the executionstreetsofboston
10/31/2022, 3:06 PMwhile (true) { }, then that while loop will not get cancelled, runInterruptable or not.Kevin Del Castillo
10/31/2022, 3:08 PMwhile (true) {} cancellable by making the suspend function cooperative adding a suspend point in between iterations, as easy as calling delay or yieldstreetsofboston
10/31/2022, 3:09 PMJoffrey
10/31/2022, 3:11 PMYup, but that is a special case, when io is blocking or something similar, something that can be interruptedYep, that's why I said that it depends on the blocking code 🙂
Joffrey
10/31/2022, 3:13 PMJoffrey
10/31/2022, 3:15 PMYep, a way to do so would be to ensure each@Rajar It still seems a bit artificial. Why do you need these functions to bemethod is a suspend one though a test.@POST/@GET/etc.
suspend? If it is because it affects something else, then maybe you should test that this "something else" works as expected instead of trying to verify the presence of suspend hereRajar
10/31/2022, 5:20 PM