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 error
Rajar
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 context
Joffrey
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 PMrunInterruptible
Kevin 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 yield
streetsofboston
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