Article

Suspending Lambdas in Kotlin

Brian Yencho

November 11, 2020

TL;DR: Use suspend { ... } to create a suspending lambda. That is all.
Photo by Rodolfo Clix

When first working with Kotlin coroutines you will quickly come across the suspend keyword as a means of marking a function as a “suspending function”. For example:

Basic format for a suspending function in Kotlin.

There are times, however, where you will run into more exotic usages. Consider the following preview function from the coroutines core library:

https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/kotlin.-suspend-function0/as-flow.html

This extension allows for a typical suspending function to be converted to a Flow. In this case, the suspend keyword is being used to describe a functional type which is suspending:

The functional type assigned to a no-argument suspending function.

This intuitively makes some sense: just as there is a way to define non-suspending functional types like () -> T, there should also be a way to define suspending ones. The example given in the documentation for the function above provides one way to get a reference to a function of such a type. Given a no-argument suspending function like

A no-argument suspending function.

A function of type suspend () -> R can then be returned via the function reference ::remoteCall. This is simply the suspending equivalent to the non-suspending case. For example, given

A typical non-suspending function of type () -> R

the function reference ::nonSuspendingCall will be of type () -> R.

The question, however, becomes: how does one define such a functional type using a lambda? Consider the following suspending function:

A suspending function with a single parameter of type (suspend (String) -> File)

The function reference ::downloadFile has a type of suspend (String) -> File and would not, for example, be suitable for use with the asFlow helper. You may be tempted to try and use the helper method by defining a lambda as follows:

This syntax does not properly produce a suspending lambda.

This does not compile, though, when called outside a suspending function and will result in the error message:

Suspend function ‘downloadFile’ should be called only from a coroutine or another suspend function

You may have guessed that verbosity can save the day here if we explicitly denote the lambda as having the suspending type we are looking for:

This syntax produces a suspending lambda but requires the type to made explicit.

This does, in fact, work but it is also not entirely satisfying: as Kotlin developers we are spoiled by type inference and feel entitled that it should exist for this case as well. Luckily there is a way to give us the result we crave with another very interesting usage of the suspend keyword in which it is prepended to the lambda definition:

This syntax produces a suspending lambda without resorting to explicit typing.

The syntax suspend { … } results in a “suspending lambda” and produces a function of type suspend () -> T, which is exactly what we are looking for. With this syntax, suspending lambdas can take their place alongside their non-suspending siblings as another valuable tool in our coroutines (and Kotlin) toolbox.



Brian writes suspending………………lambdas at Livefront .