1

Why we should use suspend? Are they used only to restrict a function not to be used outside coroutine scope or other suspend functions?

Sergio
  • 27,326
  • 8
  • 128
  • 149
mk_369
  • 51
  • 1
  • 6
  • As the keyword suspend suggests, when used on any function, it makes functions execution suspendable/synchronous where runtime waits for it's execution on certain line without proceeding further in that method execution and continues only once that execution is completed. – Jeel Vankhede Oct 20 '22 at 06:50

3 Answers3

1

If you wonder what it does, I guess you will find the answer in this near-duplicate question's answer. It basically allows to use the syntax of synchronous calls to call an asynchronous function.

If the question is "Why use async programming?", then there are probably plenty of resources explaining this on the internet. It usually allows to use threads more effectively and avoids using too many resources.

Now as to why you would want to use suspend to do that instead of callbacks, there is probably several reasons. Probably the biggest of them is to avoid the infamous "callback hell" (well known in JS): using actual callbacks creates nesting in the code. It makes the language harder to manipulate because you can't use local variables or loops as easily as with regular sequential code. With suspend functions, the code reads sequentially even though some asynchronous mechanisms are used behind the scenes to resume executing a piece of code at a later point.

Another big reason to use suspend (and more precisely the coroutines library in general) is structured concurrency. It allows to organize your asynchronous work so you don't leak anything.

Joffrey
  • 32,348
  • 6
  • 68
  • 100
0

Are they used only to restrict a function not to be used outside co routine scope or other suspend functions?

No. The main purpose of a suspend function is to suspend a coroutine it is called in to eliminate callback hell. Consider the following code with a callback:

fun interface Callback {
    fun call()
}

fun executeRequest(c: Callback) {
    // ... create new Thread to execute some request and call callback after the request is executed
    c.call()
}

On the caller side there will be:

executeRequest {
    // ... do sth after request is competed.
}

Imagine you need to make another request after that one:

executeRequest {
    // make another request
    executeRequest {
        // and another one
        executeRequest {
            // and another one ...
            executeRequest {

            }
        }
    }
}

That is a Callback Hell. To avoid it we can get rid of a Callback code and use only suspend functions:

// withContext(Dispatchers.IO) switches a coroutine's context to background thread
suspend fun executeRequest() = withContext(Dispatchers.IO) {
    // just execute request, don't create another Thread, it is already in the background Thread
    // if there is some result, return it
}

And on the caller side if there are a couple of requests, that should be executed one by one, we can call them without the Callback Hell by launching a coroutine and calling those request in the coroutine:

viewModelScope.launch {
    executeRequest()
    executeRequest()
    executeRequest()
}
Sergio
  • 27,326
  • 8
  • 128
  • 149
0

Under the hood, suspend functions provide the extra functionality (involving a hidden Continuation object) that allow their code to be stopped and resumed later from where it left off, instead of the typical limitation that all function calls in a function are called in sequence and block the thread the entire time. The keyword is there to make the syntax very simple for doing a long-running task in the background.

Three different benefits of this:

  1. No need for callbacks for long-running tasks ("callback hell")

Without suspend functions, you would have to use callbacks to prevent a long-running task from blocking the thread, and this leads to complicated-looking code that is not written in sequential order, especially when you need to do a number of long-running tasks in sequence and even more-so if you need to do them in parallel.

  1. Structured concurrency

Built-in features for automatically cancelling long-running tasks. Guarantees about shared state being correct whenever accessed despite thread switching.

  1. No need for state machines for lazy iterators

A limited set of suspend functions can be used in lazy iterator functions like the iterator { } and sequence { } builders. These are a very different kind of coroutine than the ones launched with CoroutineScopes, because they don't do anything with thread switching. The yield() suspend function in these builders' lambdas allows the code to be paused until the next item is requested in iteration. No thread is being blocked, but not because it's doing some task in the background. It instead enables code to be written sequentially and concisely without a complicated state machine.

Tenfour04
  • 83,111
  • 11
  • 94
  • 154