Under-hood trick of kotlin compiler on Coroutines

Before we dive into the details, let's first understand the basics of coroutines. In Kotlin, a coroutine is a lightweight thread that can suspend and resume execution at specific points without blocking the thread. A coroutine can be thought of as a computation that can be paused and resumed at any point in time.

The main idea behind coroutines is to provide a way to write asynchronous, non-blocking code in a synchronous style. This makes the code more readable and easier to reason about. The suspend and resume mechanism is what makes this possible.

When a coroutine suspends, it means that it is pausing its execution and giving the control back to the caller. The coroutine can suspend for various reasons, such as waiting for an I/O operation to complete, waiting for a timer to expire, network call to complete or waiting for another coroutine to complete its execution.

Coroutine Suspension and Resumption Basics

Coroutine suspension and resumption is a fundamental concept in Kotlin coroutines. It allows coroutines to pause their execution and later resume it from where they left off, without blocking the thread.

When a coroutine is suspended, it means that it has yielded control of the thread it was running on, but it has not terminated. The coroutine remains in a suspended state until it is resumed. At this point, it continues running from where it left off.

Coroutine suspension and resumption is implemented using a technique called continuation passing. A continuation is an object that represents the remaining work of a suspended coroutine. When the coroutine is resumed, the remaining work is executed using the continuation.

The Continuation Interface

In Kotlin, the Continuation interface is used to represent a continuation. It is a generic interface that takes a type parameter representing the type of value that the coroutine will produce when it completes.

Continuations are generated automatically by the Kotlin runtime and are used by the suspend and resume mechanism of coroutines.

When a coroutine is suspended, the suspend function that caused the suspension returns the Continuation object that represents the remaining work of the coroutine. The Continuation object is then passed to the suspend function that will resume the coroutine when the time is right.

The Continuation interface has a single function called resumeWith, which takes a result of type Result<T> as its argument. The Result class is a sealed class that represents either a successful result of type T, or an exception that was thrown.

The resumeWith method is called by the coroutine dispatcher when the suspended coroutine is ready to be resumed. It takes the result of the computation and passes it back to the coroutine, allowing it to continue execution from where it left off.

Here is the interface definition for Continuation in the Kotlin runtime library:

public interface Continuation<in T> {
    public val context: CoroutineContext
    public fun resumeWith(result: Result<T>)
}
        

?The?resume?and?resumeWithException?functions we are using are extension functions from the standard library that use?resumeWith.

inline fun <T> Continuation<T>.resume(value: T): Unit 
? ? resumeWith(Result.success(value))


inline fun <T> Continuation<T>.resumeWithException(
? ? exception: Throwable
): Unit = resumeWith(Result.failure(exception)) =        

The context property represents the coroutine context that the continuation is associated with. It is used to ensure that the continuation is resumed in the correct context, with the correct dispatcher and other context elements.

Details of CoroutineContext: Details on Kotlin coroutineContext | LinkedIn

Overall, the Continuation interface is an important part of the Kotlin coroutine system, as it provides a way to suspend and resume the execution of coroutines, enabling asynchronous programming and concurrency in Kotlin.

Source code for Continuation is found in below : kotlin/Continuation.kt at master · JetBrains/kotlin (github.com)

CancellableContinuation:

CancellableContinuation is an interface in Kotlin Coroutines that extends the Continuation interface. It adds the ability to cancel a coroutine and provide a cancellation token to a coroutine. A cancellation token is an object that represents the status of the cancellation process.

The CancellableContinuation interface in Kotlin is defined as follows:

public interface CancellableContinuation<in T> : Continuation<T> {
    fun cancel(cancelCause: Throwable?): Boolean
    val isActive: Boolean
}        

Here, CancellableContinuation extends the Continuation interface, which means it inherits all the properties and functions of the Continuation interface. Additionally, it defines two new properties:

  • cancel: This function takes an optional Throwable cause and returns a boolean value. It cancels the continuation with the given cancelCause and returns true if the continuation was cancelled successfully. If the continuation was already cancelled, or it has already completed, then it returns false.
  • isActive: This property returns a boolean value that indicates whether the continuation is active or not. A continuation is considered active if it has not yet completed or been cancelled. If the continuation is active, then it can be cancelled using the cancel function.


When a coroutine is cancelled, the cancel() method is called on the CancellableContinuation object, which will resume the coroutine with an exception that indicates the coroutine was cancelled. This allows the coroutine to perform any necessary cleanup actions.

CancellableContinuation provides a way to cancel a coroutine and also provides a property cancelCause to check the cancellation cause (if any) of the coroutine.

The significance of CancellableContinuation is that it provides a way to cancel a coroutine and provides a cancellation token to monitor the cancellation process. This is useful in scenarios where a long-running coroutine needs to be cancelled, such as in network or database operations.

Important to remember about continuation :

You can also see the?Continuation?interface in below 3 places

  1. Added as a last parameter to suspend function by Kotlin compiler.
  2. When converting callback-based APIs to coroutines using?suspendCoroutine?or?suspendCancellableCoroutine?(which you should always prefer), you directly interact with a?Continuation?object to resume the coroutine that got suspended after running the block of code passed as a parameter.
  3. You can start a coroutine with the?startCoroutine?extension function on a suspend function. It takes a?Continuation?object as a parameter that will get called when the new coroutine finishes with either a result or an exception.


The suspendCoroutine Function

The suspendCoroutine function is a higher-order function that takes a lambda with a single argument of type Continuation<T>. The T type parameter represents the type of value that the coroutine will produce when it completes.

The Continuation object is typically passed as the last parameter to a suspending function. This is because a suspending function can pause its execution at any point and return a Continuation object, which represents the remaining work that needs to be done after the function resumes.

The caller of a suspending function does not need to create the Continuation object explicitly. Instead, the Kotlin compiler generates the code to create the Continuation object and pass it as the last parameter when the function is called from a coroutine.

The suspendCoroutine function is used to suspend a coroutine and pass a Continuation to a callback function. The callback function can then use the Continuation to resume the coroutine when it's ready. The signature of the suspendCoroutine function is as follows:

public suspend inline fun <T> suspendCoroutine(
    crossinline block: (Continuation<T>) -> Unit
): T        

The function takes a lambda function that accepts a Continuation as its argument. The lambda function should perform some asynchronous operation and call the resume function of the Continuation when the operation is complete.

In Kotlin, a lambda or function parameter marked with the crossinline keyword cannot use the return statement to jump out of the containing function. This is because a non-local return could cause unexpected behavior in the coroutine that is suspended at the suspendCoroutine call.

In the context of the statement crossinline block: (Continuation<T>) -> Unit, it means that the lambda function block passed as an argument to the suspendCoroutine function cannot use the return statement to jump out of the containing function. This is because the block lambda contains the Continuation object which is needed to resume the suspended coroutine, and a non-local return could cause issues with the continuation flow.


Example, let's say we want to read a file asynchronously and return the contents as a string. We can use the suspendCoroutine function to suspend the coroutine and pass a Continuation to a callback function that reads the file and resumes the coroutine when it's done:

Example1

suspend fun readFile(filename: String): String = suspendCoroutine { continuation ->
    val file = File(filename)
    val reader = FileReader(file)

    reader.readLines { lines ->
        val contents = lines.joinToString("\n")
        continuation.resume(contents)
    }
}        

In the above example, the readFile function takes a filename as its argument and returns the contents of the file as a string. It uses the suspendCoroutine function to suspend the coroutine and pass a Continuation to a callback function that reads the file and resumes the coroutine with the contents of the file when it's done.

The suspendCoroutine function is used when a coroutine needs to suspend and wait for a result. It returns the value that the coroutine produced when it resumed.

2nd Example :

suspend fun getUser(userId: String): User {
    return suspendCoroutine { continuation ->
        // make a network request to get the user with the given ID
        val user = getUserFromNetwork(userId)
        continuation.resume(user)
    }
}        

In the above example, the getUser function is a suspend function that uses the suspendCoroutine function to make a network request to get a user by ID. When the network request completes, the result is passed to the resume method of the Continuation object, which resumes the coroutine and returns the user.


Please understand below about how function can be converted in to suspending function with introduction of Continuation<T>

fun backgroundTask(param: Int, callback:?Continuation<Int>): Int {

??// long running operation

}

a new?additional parameter of type?Continuation<T> is added as above .

When a coroutine suspends, it also captures its state(context,dispatcher,etc), including the local variables and the call stack. This state is saved in an object called a Continuation. The Continuation is a callback that the coroutine provides to the runtime to resume its execution at a later point.

To suspend a coroutine and obtain a Continuation object, we can use the suspendCoroutine function. The suspendCoroutine function takes a lambda with a single argument of type Continuation. This lambda represents the continuation of the coroutine. When the coroutine suspends, the lambda is called with a Continuation object that can be used to resume the coroutine.

Here is an example:

suspend fun fetchData(): String { 
    return suspendCoroutine { continuation -> 
        // Do some async work 
        val result = "data" 
        continuation.resume(result) 
    } 
}         

In this example, fetchData is a suspend function that suspends its execution and returns a Continuation object to the runtime. The runtime will call the resume function on the Continuation object when the async work is done and the coroutine can be resumed.

To resume a coroutine, we can use the resume function on the Continuation object that was obtained when the coroutine suspended. This function takes a single argument, which is the result of the async operation. The resume function will resume the coroutine with the result.

How suspend function can be converted to statemachine ?

When you mark a function with the suspend keyword, the Kotlin compiler generates the necessary code to convert the function into a state machine that can be paused and resumed. When the function is called, it will run until it encounters a suspend point (e.g. a call to another suspend function or a call to suspendCoroutine). At that point, the function will pause and return control to the caller. When the suspend function is ready to resume, it will call the resume method on the Continuation object that was passed to it.


let's discuss below example, how can a normal suspend function is converted to function with state machine.

Consider a simple suspend function that takes two integer values and returns their sum after a delay of 1 second.

suspend fun add(a: Int, b: Int): Int {
    delay(1000)
    return a + b
}        

The delay function is provided by the kotlinx.coroutines library and is a suspend function itself.

When this function is compiled by the Kotlin compiler, it will be converted into a state machine with three states:

  1. Initial state: the state machine starts in this state when add is called.
  2. Suspension state: the state machine transitions to this state when suspendCoroutine is called, and remains in this state until the asynchronous operation completes.
  3. Final state: the state machine transitions to this state when the asynchronous operation completes, and execution of add is complete.

                   +--------+
                   |Initial |
                   | State  |
                   +--------+
                        |
                        |
                        |
                        V
                +--------------+
                | Suspension   |
                | State        |
                +--------------+
                        |
                        |
                        |
                        V
                   +--------+
                   | Final  |
                   | State  |
                   +--------+        

When we call this add function in a coroutine, it will suspend the coroutine for 1 second and then return the result. However, behind the scenes, the Kotlin compiler will transform this suspend function into a state machine that can suspend and resume the execution of the function.

Here's how the state machine for this function may look like:

Note: This is just for understanding purpose, Actual state machine generation by Kotlin compiler may be different.

import kotlin.coroutines.*
import kotlinx.coroutines.*
import kotlin.coroutines.intrinsics.*

class AddStateMachine(private val a: Int, private val b: Int, 
private val continuation: Continuation<Int>) :
        Continuation<Any?> {

    // The state of the state machine
    private var state = 0

    // The result of the computation
    private var result: Int = 0

    // This function is called when the coroutine is resumed
    override fun resumeWith(result: Result<Any?>) {
        // Check the state of the state machine
        when (state) {
            // State 0 - initial state
            0 -> {
                // Save the values of a, b, and continuation to local variables
                val tmpA = a
                val tmpB = b
                val tmpContinuation = continuation

                // Transition to the next state
                state = 1

                // Call the delay function to suspend the coroutine for 1 second
                val delay = delay(1000L, tmpContinuation)

                // Check if the coroutine was cancelled while it was suspended
                if (delay != IntrinsicsKt.getCOROUTINE_SUSPENDED()) {
                    // Transition to the next state
                    state = 2

                    // Calculate the result of the computation
                    result = tmpA + tmpB

                    // Resume the coroutine with the result
                    tmpContinuation.resumeWith(Result.success(result))
                }
            }
            // State 1 - coroutine was cancelled while suspended
            1 -> {
                // Handle cancellation if needed
            }
            // If the state is anything other than 0 or 1, throw an exception
            else -> throw IllegalStateException("Unexpected state $state")
        }
    }

    // This function is called when the coroutine is cancelled
    override fun invokeOnCancellation() {
        // Handle cancellation if needed
    }

    // This function is called when the coroutine is suspended
    override fun invokeSuspend(result: Any?) {
        // Resume the coroutine with the given result
        resumeWith(result as Result<Any?>)
    }
} 

// This suspend function uses the state machine to add two numbers
suspend fun add(a: Int, b: Int): Int = suspendCoroutine { continuation ->
    // Create a new instance of the AddStateMachine class
    val stateMachine = AddStateMachine(a, b, continuation)

    // Start the state machine
    stateMachine.resume(Unit)
}

// This is the main function that starts a new coroutine and calls the add function
fun main() {
    GlobalScope.launch {
        val result1 = add(2, 3)
        val result2 = add(5, 7)
        println("Result1: $result1, Result2: $result2")
    }
    Thread.sleep(2000)
}        

AddStateMachine class is generated by the kotlin compiler which implements the Continuation. The AddStateMachine class takes three arguments: a, b, and continuation. a and b are the two numbers to be added, and continuation is the continuation that the coroutine should resume with once the computation is complete.

Inside the AddStateMachine class, there are three properties: state, result, and continuation. state keeps track of the current state of the state machine, result stores the result of the computation, and continuation stores the continuation that the coroutine should resume with.

The resumeWith function is called when the coroutine is resumed. Inside this function, there is a when statement that checks the current state of the state machine. If the state is 0, the code saves the values of a, b, and continuation to local variables and transitions to the next state (state 1). It then calls the delay function to suspend the coroutine for 1 second. If the coroutine is cancelled while it is suspended, it will be handled in the state 1. Otherwise, it calculates the result of the computation (a + b) and resumes the coroutine with the result.

The invokeOnCancellation function is called when the coroutine is cancelled. It is empty in this example.

The invokeSuspend function is called when the coroutine is suspended. It simply calls resumeWith with the given result.

The add function is a suspend function that takes two integers a and b and returns their sum. It creates a new instance of the AddStateMachine class and passes in the arguments a, b, and the current continuation. It then starts the state machine by calling resume(Unit).

Finally, the main function creates a new coroutine using GlobalScope.launch. Inside the coroutine, it calls the add function twice with different arguments and prints the results. It then sleeps for 2 seconds to give the coroutines time to complete before exiting.

I think below links are very good explanation for how suspendCoroutine is used to convert normal function to suspend function.

  1. The suspend modifier — under the hood (manuelvivo.dev)
  2. How does suspension work in Kotlin coroutines? (kt.academy)

invokeOnCompletion :

The invokeOnCompletion function is used to register a callback function that will be called when a coroutine completes. The callback function is passed a throwable that indicates the reason for completion, or null if the coroutine completed normally. The signature of the invokeOnCompletion function is as follows:

public fun Job.invokeOnCompletion(
    onCancelling: Boolean = false,
    invokeImmediately: Boolean = true,
    handler: (cause: Throwable?) -> Unit
): DisposableHandle        

The function takes a lambda function that accepts a throwable as its argument. The lambda function should perform some cleanup operation, such as releasing resources or logging, and can use the throwable to determine the reason for completion.

Here is an example:

fun main() {
    val job = GlobalScope.launch {
        val result = fetchData()
        println(result)
    }
    job.invokeOnCompletion {
        println("Coroutine completed")
    }
}        

In the above example, we launch a new coroutine using the GlobalScope.launch function. The coroutine calls the fetchData function, which suspends its execution and returns a Continuation object to the runtime. The runtime will call the resume function on the Continuation object when the async work is done and the coroutine can be resumed.

The coroutine is associated with a Job object, which is returned by the launch function. We can use the invokeOnCompletion function on the Job object to register a callback that will be called when the coroutine completes its execution.

Please note that suspendCoroutine, Continuation, and invokeOnCompletion are all part of the Kotlin runtime library and are automatically handled by the Kotlin compiler and runtime. As a developer, we don't need to call them directly or control them programmatically.

invokeOnCompletion is a method available on a Job or a Deferred object, and it allows you to specify a callback function to be executed when the job or deferred completes. This can be useful for performing cleanup operations or updating UI elements after a coroutine has finished executing.

Here's an example of how invokeOnCompletion can be used in a state machine:Here's an updated version of the CountDownStateMachine class that handles all three states:

import kotlin.coroutines.*

class CountDownStateMachine(private val n: Int, 
                            private val continuation: Continuation<Int>) :
    Continuation<Any?> {

    // The state of the state machine
    private var state = 0

    // The countdown value
    private var count = n

    // This function is called when the coroutine is resumed
    override fun resumeWith(result: Result<Any?>) {
        // Check the state of the state machine
        when (state) {
            // State 0 - initial state
            0 -> {
                // Print the current countdown value
                println(count)

                // Decrement the countdown value
                count--

                // Check if the countdown is complete
                if (count < 0) {
                    // Transition to the next state
                    state = 1

                    // Resume the coroutine with the result
                    continuation.resumeWith(Result.success(n))
                } else {
                    // Transition to the next state
                    state = 2

                    // Call the delay function to suspend the coroutine for 1 second
                    val delay = delay(1000L, continuation)

                    // Check if the coroutine was cancelled while it was suspended
                    if (delay != IntrinsicsKt.getCOROUTINE_SUSPENDED()) {
                        // Transition to the next state
                        state = 0

                        // Resume the coroutine
                        continuation.resume(Unit)
                    }
                }
            }
            // State 1 - countdown complete
            1 -> {
                // Print the message
                println("Countdown complete")
            }
            // State 2 - coroutine suspended
            2 -> {
                // Transition to the next state
                state = 0

                // Resume the coroutine
                continuation.resume(Unit)
            }
            // Invalid state
            else -> throw IllegalStateException("Unexpected state $state")
        }
    }

    // This function is called when the coroutine is cancelled
    override fun invokeOnCancellation() {
        // Handle cancellation if needed
    }

    // This function is called when the coroutine is suspended
    override fun invokeSuspend(result: Any?) {
        // Resume the coroutine with the given result
        resumeWith(result as Result<Any?>)
    }
}        

And here's the updated countDown function that uses the CountDownStateMachine class:

suspend fun countDown(n: Int): Int = suspendCoroutine { continuation ->
    // Create a new instance of the CountDownStateMachine class
    val stateMachine = CountDownStateMachine(n, continuation)

    // Start the state machine
    stateMachine.resume(Unit)
}         

Finally, here's how you can use the countDown function with the updated CountDownStateMachine class:

fun main() {
    val job = GlobalScope.launch {
        countDown(3)
    }

    job.invokeOnCompletion {
        println("Job completed")
    }

    Thread.sleep(4000)
}        

The above code demonstrates the use of Kotlin coroutines to implement a countdown timer. The countDown function takes an integer n as input and counts down from n to 0, printing each number to the console with a delay of 1 second between each count.

The main function creates a coroutine using GlobalScope.launch, which launches the countDown function as a new coroutine. It then registers an invokeOnCompletion handler on the job object, which is executed when the coroutine completes. This handler simply prints "Job completed" to the console.

Finally, the main function calls Thread.sleep(4000) to pause execution for 4 seconds, allowing the countdown coroutine to complete and the invokeOnCompletion handler to be executed.

In summary, this code shows how Kotlin coroutines can be used to create asynchronous and non-blocking code, and how invokeOnCompletion can be used to handle completion events for coroutines.

How the continuation flows from calling suspending function to the kotlin runtime:

  1. When a suspending function is called from a coroutine, the compiler generates code to suspend the coroutine and capture its continuation.
  2. The suspending function then calls suspendCoroutine function, passing in a lambda that takes a Continuation object as its argument.
  3. The suspendCoroutine function creates a CancellableContinuation object that wraps the original continuation and the current coroutine context, and then calls the lambda with this object.
  4. The suspending function's execution is now suspended, and the CancellableContinuation object is returned to the coroutine caller.
  5. When the asynchronous operation in the suspending function completes, it calls the resume method of the captured Continuation object.
  6. The resume method of the Continuation object then resumes the execution of the coroutine from where it was suspended, passing in the result of the operation as its argument.
  7. The resumed coroutine continues to execute until it either completes or suspends again on another suspending function call.
  8. If the coroutine suspends again, the process repeats from step 2 with a new CancellableContinuation object and captured continuation.
  9. When the coroutine completes, its captured continuation is discarded, and the coroutine terminates.

So, the Continuation object is passed from the coroutine caller to the suspendCoroutine function, where it is wrapped in a CancellableContinuation object and returned to the suspending function. The asynchronous operation in the suspending function then calls the resume method of the Continuation object to resume the coroutine's execution. This process repeats for each suspending function call in the coroutine.

Note: If you mark a function that doesn’t call other suspend functions such as delay or io blocking, network blocking with the suspend modifier, although the compiler will add the extra Continuation parameter but won’t do anything with it, the function body’s bytecode will look like a regular function.

Lets see how kotlin compiler may change the code with the introduction of continuation , suspendCoroutine and resume .

Example1:

suspend fun printWithDelay(message: String, delay: Long) {
    delay(delay)
    println(message)
}

fun main() {
    GlobalScope.launch {
        printWithDelay("Hello", 1000)
        printWithDelay("World", 1000)
    }
    Thread.sleep(2000)
}        

Below is modifications that the Kotlin compiler would make for introducing the Continuation object and the SuspendCoroutine function:

suspend fun printWithDelay(message: String, delay: Long, continuation: Continuation<Unit>) 
    // 1. Save the current continuation
    val current = continuation.context[ContinuationInterceptor]!!.interceptContinuation(continuation)

    // 2. Schedule a delayed task
    GlobalScope.launch {
        delay(delay)

        // 3. Resume the continuation in the original context
        current.resume(Unit)
    }

    // 4. Suspend the coroutine
    return suspendCoroutine { /* nothing to do here */ }
}

fun main() {
    GlobalScope.launch {
        printWithDelay("Hello", 1000, continuation)
        printWithDelay("World", 1000, continuation)
    }
    Thread.sleep(2000)
}{        

  1. Adding a Continuation<Unit> parameter to the printWithDelay function signature to receive the continuation object.
  2. Saving the current continuation object and scheduling a delayed task in the coroutine's original context (with GlobalScope.launch).
  3. Resuming the saved continuation object in the original context after the delay is completed (with current.resume(Unit)).
  4. Suspending the coroutine by calling suspendCoroutine and passing an empty lambda as the argument.

Note1: that in the main function, we need to pass the continuation object to each invocation of the printWithDelay function. This is because the Continuation object is not automatically provided by the Kotlin compiler for top-level coroutines like those created by GlobalScope.launch. Instead, we need to explicitly pass the continuation object to the printWithDelay function.

Note2: The suspendCoroutine function is used to suspend the coroutine execution and wait for the result of an asynchronous operation. In the above code, it is used to suspend the execution of the printWithDelay function until the delay function completes its execution.

When the delay function is called, it schedules the coroutine for resumption after the specified delay time. The coroutine is then suspended and the control is returned to the suspendCoroutine function.

The suspendCoroutine function creates a new Continuation object and passes it to the lambda function. The lambda function can use this continuation object to resume the coroutine execution when the result of the asynchronous operation is available.

In the above code, since the delay function is a suspending function, it expects a Continuation object as its last parameter. Since we are not interested in handling the continuation object explicitly, we can simply return the suspendCoroutine function without doing anything. This allows the delay function to handle the continuation object and resume the coroutine execution when the delay is completed.


When we call async, it internally creates a coroutine, and the suspend lambda function passed to it is executed in that coroutine. The async function returns an instance of Deferred which represents a value that will be computed asynchronously.

When we call await() function on Deferred instance, the suspend function inside the async coroutine is suspended and it creates a continuation object which is passed to the suspendCoroutine function internally. The suspendCoroutine function then passes the continuation object to the block lambda function which was passed to the async function.

So, in the case of async function, the continuation object is implicitly handled by the suspendCoroutine function and there is no need to pass it as the last parameter explicitly.

Final words:

As a programmer, you may not need to use Continuation, invokeOnCompletion, suspendCoroutine, and resume directly in your code most of the time. These are lower-level constructs used by Kotlin runtime to implement coroutines and provide a way to manage the suspension and resumption of coroutine execution.

However, you can use suspendCoroutine in some cases to create your own suspending functions. For example, if you have a long-running operation that you want to expose as a suspending function, you can use suspendCoroutine to create a function that suspends the coroutine until the operation completes.

Similarly, you can use invokeOnCompletion to register a callback that is called when a coroutine completes. This can be useful for cleaning up resources or performing some other action after a coroutine has finished.

Overall, as a programmer, you should focus on using the higher-level abstractions provided by Kotlin coroutines, such as async, launch, withContext, and delay, instead of using the lower-level constructs directly. These higher-level constructs provide an easier and more intuitive way to write asynchronous and concurrent code.


Things to remember:

public interface Continuation<in T> {
    public val context: CoroutineContext
    public fun resumeWith(result: Result<T>)
}

public interface CancellableContinuation<in T> : Continuation<T> {
    fun cancel(cancelCause: Throwable?): Boolean
    val isActive: Boolean
}

public suspend inline fun <T> suspendCoroutine(
    crossinline block: (Continuation<T>) -> Unit
): T

public fun Job.invokeOnCompletion
    onCancelling: Boolean = false,
    invokeImmediately: Boolean = true,
    handler: (cause: Throwable?) -> Unit
): DisposableHandle(        


Thanks for reading till end. Please suggest or comment of you have any .

要查看或添加评论,请登录

Amit Nadiger的更多文章

  • Passing imp DS(vec,map,set) to function

    Passing imp DS(vec,map,set) to function

    In Rust, we can pass imp data structures such as , , and to functions in different ways, depending on whether you want…

  • Atomics in C++

    Atomics in C++

    The C++11 standard introduced the library, providing a way to perform operations on shared data without explicit…

    1 条评论
  • List of C++ 11 additions

    List of C++ 11 additions

    1. Smart Pointers Types: std::unique_ptr, std::shared_ptr, and std::weak_ptr.

    2 条评论
  • std::lock, std::trylock in C++

    std::lock, std::trylock in C++

    std::lock - cppreference.com Concurrency and synchronization are essential aspects of modern software development.

    3 条评论
  • std::unique_lock,lock_guard, & scoped_lock

    std::unique_lock,lock_guard, & scoped_lock

    C++11 introduced several locking mechanisms to simplify thread synchronization and prevent race conditions. Among them,…

  • Understanding of virtual & final in C++ 11

    Understanding of virtual & final in C++ 11

    C++ provides powerful object-oriented programming features such as polymorphism through virtual functions and control…

  • Importance of Linux kernal in AOSP

    Importance of Linux kernal in AOSP

    The Linux kernel serves as the foundational layer of the Android Open Source Project (AOSP), acting as the bridge…

    1 条评论
  • AOSP

    AOSP

    Android System Development AOSP stands for the Android Open Source Project. Its the foundation of the Android operating…

  • Creating a String from a string literal (&str)

    Creating a String from a string literal (&str)

    Different methods to create a from a string literal () are as follows : 1. to_owned() The to_owned() method is a…

  • Reducing the size of Rust Executables

    Reducing the size of Rust Executables

    First of all why are Rust Executables Large? Debug Symbols: By default, Rust includes debug symbols in the binary for…

社区洞察

其他会员也浏览了